使用 Places API 沿路搜尋

本文說明如何沿著規劃路線尋找飯店、餐廳或加油站。您將瞭解如何使用 Routes API 取得路線折線,並搭配 Places API Search Along Route (SAR) 要求使用。您也會瞭解如何沿路線設定搜尋起點 (例如旅程開始 2 小時後),取得最佳結果。

Routes API

如要搜尋路線沿途的地點,我們將使用 Routes API。Routes API 回應中的路徑資料是一連串從起點到目的地的 LatLong 座標。路線資料包含路段和步驟,這些資料會遵循道路網路。

路線也會以編碼折線的形式傳回,您可將其做為輸入參數傳遞至 SAR 要求。折線編碼是一種有損壓縮演算法,可將一系列座標儲存為單一字串。從 Routes API 取得折線並非必要步驟。您可以自行建立資料,但就本範例而言,Routes API 是快速且可靠的必要資料取得方式。

在本教學課程中,我們會使用從倫敦 (-37.8167,144.9619) 到曼徹斯特 (-37.8155, 144.9663) 的路線。

從倫敦到曼徹斯特的路線

範例路線:倫敦到曼徹斯特

步驟 1:從 Routes API 取得路線

如要透過 Routes API 取得路線,您必須提供下列資訊:

  • 出發地和目的地
  • 交通方式 (開車、步行等)
  • 任何中途點 (選填)
  • 任何偏好設定 (避開收費路段、避開高速公路等)
  • 「Traffic aware routing preference」可提供最精確的預估值,但運算量較大,因此會增加回應延遲時間。
{"origin":{
    "location": {
        "latLng":{
            "latitude":  -37.8167,
            "longitude": 144.9619
        }
    }
},
"destination":{
    "location": {
        "latLng":{
            "latitude":-37.8155,
            "longitude": 144.9663
        }
    }
},
"routingPreference":"TRAFFIC_AWARE",
"travelMode":"DRIVE"
}

進行呼叫時,請務必在標頭欄位遮罩中加入「encodedPolyline」欄位。

headers = {
    "Content-Type": "application/json",
    "X-Goog-FieldMask": "routes.distanceMeters,routes.duration,routes.legs,routes.polyline.encodedPolyline"
}

如需完整說明文件,以及如何取得路線取得路線折線的範例,請參閱相關說明文件。

在要求中提供這項資訊後,Routes API 就會傳回路徑物件。路線物件會包含下列資訊:

  • 路線總距離
  • 路線總時間
  • 路線的各段路程和步驟
  • 路線、路段和步驟的編碼折線。
{
  "routes": [
    {
      "legs": [
        {
          "distanceMeters": 321799,
          "duration": "15401s",
          "staticDuration": "14518s",
          "polyline": {
            "encodedPolyline": "y_kyH`_XOr@q@xKGnBBZ|AlGPj@Y^k@^MEqAfAQLK?eI … <rest of content removed for readability>"
          },
          "startLocation": {
            "latLng": {
              "latitude": 51.507334500000006,
              "longitude": -0.1280107
            }
          },
          "endLocation": {
            "latLng": {
              "latitude": 53.4808513,
              "longitude": -2.2425864
            }
          },
          "steps": [
            {
              "distanceMeters": 320,
              "staticDuration": "82s",
              "polyline": {
                "encodedPolyline": "y_kyH`_XOr@q@xKGnBBZ|AlG"
              },
              "startLocation": {
                "latLng": {
                  "latitude": 51.507334500000006,
                  "longitude": -0.1280107
                }
              },
              "endLocation": {
                "latLng": {
                  "latitude": 51.507207,
                  "longitude": -0.1323681
                }
              },
              "navigationInstruction": {
                "maneuver": "DEPART",
                "instructions": "Head northwest on Trafalgar Sq/A4 toward Spring Gardens\nContinue to follow A4\nLeaving toll zone\nEntering toll zone\nLeaving toll zone in 210m at Haymarket"
              },
              "localizedValues": {
                "distance": {
                  "text": "0.3 km"
                },
                "staticDuration": {
                  "text": "1 min"
                }
              },
# rest of the response removed for readability

步驟 2:搜尋「沿途搜尋」要求

Places API 文字搜尋服務提供「沿途搜尋」要求,可讓您搜尋路線沿途的地點。如要提出「沿途搜尋」要求,您至少需要提供下列資訊:

  • 欄位遮罩,用於指定要在回應中傳回哪些欄位
  • 在 Google Cloud 控制台中啟用的 API 適用的有效 API 金鑰
  • 搜尋文字字串,說明您要尋找的地點,例如「辣味素食餐廳」
  • 從先前的 Routes API 呼叫擷取的路線編碼折線
  • Places Text Search API 端點的網址
import requests

url = 'https://places.googleapis.com/v1/places:searchText'
api_key = 'YOUR_API_KEY'  # Replace with your actual API key
route_polyline = 'YOUR_ROUTE_POLYLINE'  # Replace with your encoded route polyline

headers = {
    'Content-Type': 'application/json',
    'X-Goog-Api-Key': api_key,
    'X-Goog-FieldMask': 'places.displayName,places.formattedAddress,places.priceLevel'
}

data = {
    "textQuery":
 "Spicy Vegetarian Food",
    "searchAlongRouteParameters": {
        "polyline": {
            "encodedPolyline": route_polyline
        }
    }
}

response = requests.post(url, headers=headers, json=data)

要求資料範例

「沿途搜尋」要求會傳回沿途的地點清單。以下是範例資料的一小部分。您可以設定結果數量上限參數,限制回應長度,新增更多欄位也會增加收到的資料量。如要進一步瞭解 Places API 回應,請參閱說明文件

{
  "places": [
    {
      "formattedAddress": "33 Haymarket, London SW1Y 4HA, UK",
      "displayName": {
        "text": "xxx",
        "languageCode": "en"
      }
    },
    {
      "formattedAddress": "224 Piccadilly, London W1J 9HP, UK",
      "priceLevel": "PRICE_LEVEL_MODERATE",
      "displayName": {
        "text": "yyy",
        "languageCode": "en"
      }
    },
    {
      "formattedAddress": "63 Neal St, London WC2H 9PJ, UK",
      "displayName": {
        "text": "zzz",
        "languageCode": "en"
      }
    },

回應資料範例

路線摘要和繞道時間

找到地點固然很棒,但如果能加上前往這些地點所需的時間資訊,會更有幫助。在 Places API Text Search 中,SAR 也會傳回 routing summaries 欄位,其中包含旅行時間和距離。路徑摘要資料欄位是回應根層級的子項,因此您不得在欄位遮罩中加入「places.」前置字元。

'X-Goog-FieldMask': 'places.displayName,places.formattedAddress,places.priceLevel,routingSummaries'

如要取得摘要,您也必須提供用於計算的搜尋來源位置參數。

"routingParameters": {
      "origin": {
        "latitude":  -37.8167,
        "longitude": 144.9619
      }
    }

收到回覆時,會看到包含「路徑摘要」的新專區,其中包含以公尺為單位的時間長度和距離

"routingSummaries": [
    {
      "legs": [
        {
          "duration": "662s",
          "distanceMeters": 3093
        }
      ]
    },

接著,我們來看看如何定義路線上的搜尋起點。

步驟 3:取得路線上 2 小時後的所在位置

假設駕駛人想在路線中途尋找餐廳,以我們的例子來說,從倫敦到曼徹斯特的車程約為 4 小時。駕駛人想在路線上 2 小時車程處尋找餐廳。這項要求會取得 120 分鐘 * 60 秒 = 7200 秒的時長。

在 Routes API 回應中,我們有路徑每個路段和路段每個步驟的持續時間。請務必在要求中的欄位遮罩中加入「legs」欄位。重複執行上述步驟,直到累積時間達到 2 小時或 7200 秒的上限為止。然後我們找到要設為 SAR 要求來源的航段和步驟

如要加快工作速度,建議試用 Python 適用的折線程式庫。您可以使用這項工具,從「polyline.endodedPolyline」資料欄位取得座標。

在環境終端機中執行下列指令。

> pip install polyline
import requests
import polyline

# We've covered getting a Routes API response earlier,
data = response.json()

  # Extract the first route and its encoded polyline
  route = data["routes"][0]
  polyline_points = polyline.decode(route["polyline"]["encodedPolyline"])

  # Calculate total duration of the route in seconds
  total_duration_seconds = route["duration"]

  # Calculate the desired time offset in seconds, 2h = 120 minutes * 60
  desired_time_offset_seconds = time_offset_minutes * 60

  # Iterate through the legs and steps to find the point at the desired time offset
  elapsed_time_seconds = 0
  for leg in route["legs"]:
      for step in leg["steps"]:
          step_duration_seconds = step["staticDuration"]

          # Check if the desired time offset falls within this step, remove last "s" from string and convert to int
          second_value = int(step_duration_seconds[:-1])
          if elapsed_time_seconds + second_value >= desired_time_offset_seconds:
              # Interpolate to find the exact point within the step
              fraction_of_step = (desired_time_offset_seconds - elapsed_time_seconds) / second_value
              step_polyline_points = polyline.decode(step["polyline"]["encodedPolyline"])
              index = int(len(step_polyline_points) * fraction_of_step)
              return step_polyline_points[index]

          elapsed_time_seconds += second_value

  # If the point is not found (e.g., time offset exceeds route duration)
  return None

現在我們已在路線上找到行程開始後 2 小時的位置,可以將該位置用於要求。只要在「origin」參數中加入經緯度即可,而「origin」參數本身是「routingParameters」參數的一部分。建議使用先前介紹的「routingSummaries」資料欄位。你也可以新增其他參數,例如交通方式和避開收費路段的指示。


"routingParameters": {
    "origin": {
      "latitude": xx.xxxx,
      "longitude": yy.yyyy
    },
    "travelMode":"DRIVE",
    "routeModifiers": {
      "avoidTolls": true
    }
  }

路線和搜尋結果

結果範例 (新增車輛圖示,顯示搜尋來源)。

如圖片所示,API 傳回的地點偏向路線終點,結果從行程中途開始。搜尋功能仍採用相同的 Google 地圖平台資料,並將地點相關性和距離等因素納入考量。

結語

在本教學課程中,我們瞭解如何結合使用 Google 地圖平台 API (Routes 和 Places),規劃行程並在旅程開始 2 小時後尋找用餐地點。您需要採取以下步驟:取得含有路徑中每個步驟的緯度和經度座標的編碼折線,並設定「沿途搜尋」要求來源,以取得最佳結果。

這項功能為 Places API 中現有的文字搜尋和附近搜尋功能,新增了強大的工具。接下來的邏輯步驟是新增位置資訊服務,這樣您就能以駕駛人的位置做為起點,找出最佳搜尋來源。此外,這項功能還能與車內語音助理完美搭配,只要說出偏好的用餐選項,就能輕鬆完成預訂。

後續動作

建議延伸閱讀:

貢獻者

Google 會維護這份文件。這篇文章最初是由下列貢獻者撰寫。

主要作者:Mikko Toivanen | Google 地圖平台解決方案工程師