Geocoding v3 から v4 に移行する

欧州経済領域(EEA)のデベロッパー

Geocoding API v4 では、API の v3 の機能を置き換えるいくつかの新しいメソッドが導入されています。このガイドでは、新しい v4 メソッドを使用するようにアプリを移行する方法について説明します。

既存の API キーを新しい v4 メソッドで使用できます。ただし、API の v3 で割り当ての引き上げをリクエストした場合は、新しい v4 API で引き上げをリクエストする必要があります。

v3 のフォワード ジオコーディングから移行する

v3 Geocoding を使用して住所をジオコーディングしている場合は、GET リクエストを受け入れる v4 の 住所をジオコーディングするメソッドに移行する必要があります。

v4 API では、いくつかのパラメータの名前、構造、サポートが変更されています。フィールド マスクを使用して、レスポンスで返すフィールドを指定することを強くおすすめします。

リクエスト パラメータの変更

v3 パラメータ v4 パラメータ メモ
address、components address 非構造化アドレス(v3 address)が URL パスで渡されるようになりました。構造化された住所コンポーネント(v3 components)は、address.* クエリ パラメータとして渡すことができます。v3 コンポーネント フィルタを再現するをご覧ください。
bounds locationBias.rectangle 名前を変更。構造をオブジェクトに変更。
language languageCode 名前を変更しました。省略した場合、v3 では Accept-Language ヘッダーが使用されるか、デフォルトで en が使用されます。一方、v4 では、デフォルトでその場所の現地の言語と文字が使用されます。
region regionCode 名前を変更しました。省略すると、v3 のデフォルトは us になりますが、v4 にはデフォルト値がありません。
extra_computations 削除済み SearchDestinations メソッドに置き換えられました。

レスポンス フィールドの変更

v3 フィールド v4 フィールド メモ
status、error_message 削除済み v4 では HTTP ステータス コードとエラー本文を使用します。
results.address_components.long_name / results.address_components.short_name results.addressComponents.longText / results.addressComponents.shortText 名前を変更しました。
results.geometry.location_type results.granularity 名前を変更しました。
results.geometry.location results.location フィールド名: lat/lng -> latitude/longitude。
results.geometry.viewport results.viewport フィールド名: northeast/southwest -> high/low。
results.postcode_localities results.postalCodeLocalities 名前を変更しました。1 つ以上の地域に対して返されるようになりました(v3 では 1 つ以上が必要)。
results.partial_match 削除済み
新機能 results.addressComponents.languageCode 特定のアドレス コンポーネントの言語。
新機能 results.bounds high / low を使用した明示的な境界。
新機能 results.place 場所のリソース名。
新機能 results.postalAddress 構造化された PostalAddress オブジェクト。

v3 コンポーネント フィルタを再現する

Geocoding v3 のフォワード ジオコーディングには、特定のコンポーネント(components=country:US など)の結果をハード フィルタリングできる components パラメータが含まれていました。v4 のフォワード ジオコーディングでは、リクエスト パラメータでのこのタイプのハード フィルタリングはサポートされていません。v4 では、住所情報をパス内の単一の非構造化文字列として指定することも、address.addressLines、address.locality、address.administrativeArea、address.postalCode、address.regionCode などの構造化クエリ パラメータとして指定することもできます。構造化パラメータは、ハードフィルタとして機能しません。代わりに、指定されたすべてのコンポーネントが結合され、API がジオコーディングを試みる完全な住所が形成されます。API は、すべてのコンポーネントで指定された住所全体に最も一致するものを検索します。コンポーネントを構造化された方法で提供すると、特に住所情報が個別のフォーム フィールドから収集される場合に、API が意図をより適切に理解できるようになります。各フィールドの情報タイプが明確であるため、API が各コンポーネント内の軽微な入力ミスや曖昧さを処理するのに役立ちます。

v3 のハード コンポーネント フィルタと同様の動作を実現するには、レスポンスの postalAddress オブジェクトと addressComponents オブジェクトに基づいて、v4 API から返された results 配列にクライアントサイド フィルタを実装する必要があります。

次の表に、v3 components フィルタと v4 postalAddress フィールドの最適な一致を示します。

v3 コンポーネント フィルタ v4 レスポンス フィールド
country postalAddress.regionCode
postal_code postalAddress.postalCode
administrative_area postalAddress.administrativeArea または addressComponents

クライアントサイドのフィルタリングの例

次の例は、サポートされているフィールド(国、行政区域、郵便番号)で v3 コンポーネント フィルタリングと同様の動作を実現するために、結果をフィルタリングする方法を示しています。信頼できるフィルタリング条件が存在しないため、他のフィールドでフィルタリングすることはおすすめしません。

国でフィルタ

リクエストの address.regionCode と各結果の postalAddress.regionCode を照合します。API はリクエストで小文字の地域コードを受け入れますが、レスポンスでは常に大文字で返します。そのため、比較する前に、入力を大文字に正規化する必要があります。

Python コードの例
def filter_by_country(results, region_code):
    return [
        res for res in results
        if res.get('postalAddress', {}).get('regionCode') == region_code.upper()
    ]

# Example usage:
# v4_response = ... # API call response
# filtered = filter_by_country(v4_response.get('results', []), 'US')
Node.js のコード例
function filterByCountry(results, regionCode) {
    return results.filter(res => res.postalAddress?.regionCode === regionCode.toUpperCase());
}

// Example usage:
// const v4Response = ... # API call response
// const filtered = filterByCountry(v4Response.results, 'US');
行政区域でフィルタ

リクエストの address.administrativeArea と各結果の postalAddress.administrativeArea を照合します。国コードと同様に、比較する前に、入力を大文字に正規化する必要があります。これは、リクエストの administrativeArea に標準の 2 文字の略称が指定されている場合にのみ信頼できます。レスポンスの postalAddress.administrativeArea が ISO 3166-2 コードのサフィックスと直接一致しない理由はいくつかあります。まず、一部の地域では、ISO 3166-2 コードに対応する区分が、郵便番号の標準的な表記に含まれていません。たとえば、スペインでは、行政区域レベル 1(例: カナリア諸島の「CN」)が addressComponents に含まれる場合がありますが、postalAddress.administrativeArea にはレベル 2 の区域(例: 「サンタ クルス デ テネリフェ」)が含まれる場合があります。次に、一部の地域では、行政区画の略称が一般的に使用されておらず、postalAddress.administrativeArea では長い名前で表されます(同様の理由で、行政区画に対応する住所コンポーネントの addressComponents.shortText が、行政区画の ISO 3166-2 コードのサフィックスと一致しない場合があります)。また、場合によっては、administrative_area_level_n の住所コンポーネントで、n が 1 より大きい値で表されることもあります。 最も包括的な結果を得るには、postalAddress.administrativeArea と administrative_area_level_n タイプ(administrative_area_level_1 など)の addressComponents の両方で一致を確認する必要があります。

Python コードの例
def filter_by_admin_area(results, admin_area):
    target = admin_area.upper()
    filtered = []
    for res in results:
        # Check postalAddress
        pa_aa = res.get('postalAddress', {}).get('administrativeArea', '')
        if pa_aa == target:
            filtered.append(res)
            continue
        # Check all administrative area levels in addressComponents
        for comp in res.get('addressComponents', []):
            is_admin_level = any(t.startswith('administrative_area_level_')
                               for t in comp.get('types', []))
            if is_admin_level:
                short = comp.get('shortText', '')
                if short == target:
                    filtered.append(res)
                    break
    return filtered

# Example usage:
# filtered = filter_by_admin_area(v4_response.get('results', []), 'CA')
Node.js のコード例
function filterByAdminArea(results, adminArea) {
    const target = adminArea.toUpperCase();
    return results.filter(res => {
        // Check postalAddress.administrativeArea
        if (res.postalAddress?.administrativeArea === target) {
            return true;
        }
        // Check addressComponents for any administrative area level
        return res.addressComponents?.some(c => {
            const isAdmin = c.types?.some(t => t.startsWith('administrative_area_level_'));
            return isAdmin && c.shortText === target;
        });
    });
}

// Example usage:
// const filtered = filterByAdminArea(v4Response.results, 'CA');
郵便番号でフィルタ

リクエストの address.postalCode と各結果の postalAddress.postalCode を照合します。比較する前に、入力郵便番号と結果の郵便番号の両方を正規化する必要があります。正規化ロジックはリージョンに大きく依存します。基本的なアプローチとしては、スペースとハイフンを削除し、一貫した大文字と小文字に変換します。

郵便番号の接頭辞(英国の「L2」など)や接尾辞(米国の郵便番号の「+4」など)を処理するには、より高度な正規化が必要になる場合があります。必要な正規化ロジックは、国や郵便番号の形式によって異なります。提供されている正規化関数を調整するか、ターゲットとする地域向けに、より高度なロジックを実装する必要があるかもしれません。

提供されている例では、米国の郵便番号を処理し、ZIP+4 が提供または返された場合でも、5 桁のベースで一致させることができます。

Python コードの例(米国の郵便番号に焦点を当てたもの)
import re

def normalize_postal_code_us(pc):
    # Basic normalization for US: uppercase, alphanumeric only
    if not pc:
        return ""
    normalized = re.sub(r'[^A-Z0-9]', '', pc.upper())
    # Return only the first 5 digits for US ZIP codes
    return normalized[:5]

def filter_by_postal_code_us(results, postal_code):
    normalized_input = normalize_postal_code_us(postal_code)
    if not normalized_input:
        return []
    filtered_results = []
    for res in results:
        pa_pc = res.get('postalAddress', {}).get('postalCode', '')
        if normalize_postal_code_us(pa_pc) == normalized_input:
            filtered_results.append(res)
    return filtered_results

# Example usage:
# Matches '94043', '94043-1351', '940431351'
# filtered = filter_by_postal_code_us(v4_response.get('results', []), '94043')
# filtered = filter_by_postal_code_us(v4_response.get('results', []), '94043-1234')
Node.js コードの例(米国の郵便番号に焦点を当てたもの)
function normalizePostalCodeUs(pc) {
    // Basic normalization for US: uppercase, alphanumeric only
    const normalized = (pc || '').toUpperCase().replace(/[^A-Z0-9]/g, '');
    // Return only the first 5 digits for US ZIP codes
    return normalized.substring(0, 5);
}

function filterByPostalCodeUs(results, postalCode) {
    const normalizedInput = normalizePostalCodeUs(postalCode);
    if (!normalizedInput) {
        return [];
    }
    return results.filter(res => {
        const paPc = res.postalAddress?.postalCode || '';
        return normalizePostalCodeUs(paPc) === normalizedInput;
    });
}

// Example usage:
// Matches '94043', '94043-1351', '940431351'
// const filtered = filterByPostalCodeUs(v4Response.results, '94043');
// const filtered = filterByPostalCodeUs(v4Response.results, '94043-1234');

v3 リバース ジオコーディングから移行する

v3 リバース ジオコーディングを使用して座標を住所に変換している場合は、GET リクエストを受け入れる v4 の場所をリバース ジオコーディングするメソッドに移行する必要があります。

v4 API では、いくつかのパラメータの名前、構造、サポートが変更されています。フィールド マスクを使用して、レスポンスで返すフィールドを指定することを強くおすすめします。

リクエスト パラメータの変更

v3 パラメータ v4 パラメータ メモ
language languageCode 名前を変更しました。省略した場合、v3 では Accept-Language ヘッダーが使用されるか、デフォルトで en が使用されます。一方、v4 では、デフォルトでその場所の現地の言語と文字が使用されます。
region regionCode 名前を変更しました。省略すると、v3 のデフォルトは us になりますが、v4 にはデフォルト値がありません。
result_type types 名前を変更。繰り返しクエリ パラメータを使用します。
location_type granularity 名前を変更。繰り返しクエリ パラメータを使用します。
extra_computations 削除済み SearchDestinations メソッドに置き換えられました。

レスポンス フィールドの変更

v3 フィールド v4 フィールド メモ
status、error_message 削除済み v4 では HTTP ステータス コードとエラー本文が使用されます。
results.address_components.long_name / results.address_components.short_name results.addressComponents.longText / results.addressComponents.shortText 名前を変更しました。
results.geometry.location_type results.granularity 名前を変更しました。
results.geometry.location results.location フィールド名: lat/lng -> latitude/longitude。
results.geometry.viewport results.viewport フィールド名: northeast/southwest -> high/low。
新機能 results.addressComponents.languageCode 特定のアドレス コンポーネントの言語。
新機能 results.bounds high / low を使用した明示的な境界。
新機能 results.place 場所のリソース名。
新機能 results.postalAddress 構造化された PostalAddress オブジェクト。

v3 Address descriptors から移行する

Geocoding API v3 では、extra_computations=ADDRESS_DESCRIPTORS を渡すと、landmarks[] と areas[] を含む address_descriptor オブジェクトが返されました。Geocoding API v4 では、この機能は SearchDestinations メソッド(POST /v4/geocode/destinations)に置き換えられ、各 Destination オブジェクト内で豊富な空間コンテキストが直接返されます。

次の表に、以前の v3 address_descriptor フィールドと、それに対応する v4 SearchDestinations フィールドを示します。

v3 address_descriptor フィールド v4 SearchDestinations フィールド 移行メモ
landmarks[] destinations[].landmarks[] X-Goog-FieldMask で destinations.landmarks をリクエストします。
landmarks[].place_id landmarks[].place.placeId place(PlaceView)オブジェクト内にラップされます。
landmarks[].display_name landmarks[].place.displayName ローカライズされたテキスト(text と languageCode)。
landmarks[].types landmarks[].place.types 場所タイプの文字列の配列。
landmarks[].spatial_relationship landmarks[].relationalDescription v4 では、未加工の列挙型(ACROSS_THE_ROAD、AROUND_THE_CORNER)ではなく、ローカライズされた対人可読フレーズ("Across from Central Park" など)が返されます。
landmarks[].straight_line_distance_meters landmarks[].straightLineDistanceMeters lowerCamelCase に変更しました。
landmarks[].travel_distance_meters landmarks[].travelDistanceMeters lower camelCase に名前を変更しました。
areas[](containment 列挙型) destinations[].containingPlaces[]、subDestinations[] 構造階層に最も近い同等のもの: 囲まれた複合施設、キャンパス、モール、建物は、containingPlaces[] と subDestinations[] の構造化された PlaceView オブジェクトとして返されます(structureType は GROUNDS または BUILDING に設定され、オプションで displayPolygon アウトラインが設定されます)。近隣地域 / 地区の近接エリアや、v3 の containment 列挙型(NEAR、WITHIN、OUTSKIRTS)に直接対応する代替手段はありません。

v3 のプレイス ジオコーディングから移行する

place_id を使用して Geocoding v3 で特定のプレイス ID の住所を取得する場合は、GET リクエストを受け入れる v4 の Place Geocoding メソッドに移行する必要があります。

v4 API では、いくつかのパラメータの名前、構造、サポートが変更されています。フィールド マスクを使用して、レスポンスで返すフィールドを指定することを強くおすすめします。

リクエスト パラメータの変更

v3 パラメータ v4 パラメータ メモ
place_id リクエスト proto の place フィールド プレイス ID は、パスパラメータ places/{place} として指定されるようになりました(例: https://geocode.googleapis.com/v4/geocode/places/ChIJj61dQgK6j4AR4GeTYWZsKWw)。これは、基盤となるリクエストの place フィールドにマッピングされます。
language languageCode 名前を変更しました。省略した場合、v3 では Accept-Language ヘッダーが使用されるか、デフォルトで en が使用されます。一方、v4 では、デフォルトでその場所の現地の言語と文字が使用されます。
region regionCode 名前を変更しました。省略すると、v3 のデフォルトは us になりますが、v4 にはデフォルト値がありません。

レスポンス フィールドの変更

v3 フィールド v4 フィールド メモ
status、error_message 削除済み v4 では HTTP ステータス コードとエラー本文が使用されます。
results (root) v4 は、results 配列ではなく、単一の結果オブジェクトを返します。
results.address_components.long_name / results.address_components.short_name addressComponents.longText / addressComponents.shortText 名前を変更しました。
results.geometry.location_type granularity 名前を変更しました。
results.geometry.location location フィールド名: lat/lng -> latitude/longitude。
results.geometry.viewport viewport フィールド名: northeast/southwest -> high/low。
results.postcode_localities postalCodeLocalities 名前を変更しました。1 つ以上の地域に対して返されるようになりました(v3 では 1 つ以上が必要)。
新機能 addressComponents.languageCode 特定のアドレス コンポーネントの言語。
新機能 bounds high / low を使用した明示的な境界。
新機能 place 場所のリソース名。
新機能 postalAddress 構造化された PostalAddress オブジェクト。

Geocoding Hyperlocal Data から Destinations に移行する

Geocoding API v3 の次の機能は、Geocoding API v4 の SearchDestinations メソッドに置き換えられます。

  • 閲覧開始数
  • ナビゲーション ポイント
  • 建物の輪郭
  • 邸宅と庭園

上記の機能に Geocoding API v3 を使用していた場合は、このドキュメントを参考にして、代わりに SearchDestinations メソッドを使用してこれらの機能を取得してください。このドキュメントでは、SearchDestinations レスポンスでこれらの機能を確認する方法と、Geocoding API v3 と Geocoding API v4 の SearchDestinations メソッドの間で、これらの機能が API レスポンスでどのように表現されるかの違いについて説明します。

閲覧開始数

destination に関連付けられたエントランスを取得するには、destination.entrances フィールドを使用します。

destination.entrances の各 entrance には、次のフィールドがあります(以前の v3 buildings.entrances スキーマを置き換えます)。

  • displayName - 入口の対人可読名(例: "Gate B")を含む新しいオプション フィールド。
  • location - latitude と longitude を使用した LatLng タイプの場所(v3 の lat / lng を置き換えるもの)。
  • tags - Geocoding API v3 のエントランス(PREFERRED など)の tags フィールドと同じです。
  • place - 場所のリソース名(例: places/ChIJ...)。Geocoding API v3 の building_place_id フィールドに代わるものです。v4 では、この場所は建物だけでなく、目的地となる構造物(建物、キャンパス、公園)を表すことができます。

destination に関連付けられたナビゲーション ポイントを取得するには、destination.navigationPoints フィールドを使用します。

destination.navigationPoints の各 navigationPoint には、次のフィールドがあります(以前の v3 navigation_points スキーマを置き換えます)。

  • navigationPointToken - Routes API の ComputeRoutes メソッド(Waypoint.navigationPointToken)で、この特定のナビゲーション ポイントへのルート設定に使用される暗号化されたトークン文字列。ナビゲーション ポイント トークンを使用してルートを設定するをご覧ください。
  • displayName - ナビゲーション ポイントの人が読める形式の名前(例: "5th Ave")を含む新しいオプション フィールド。
  • location - latitude と longitude を使用した LatLng タイプのロケーション。
  • travelModes - Geocoding API v3 の restricted_travel_modes フィールドに似ていますが、v4 では制限された移動手段ではなく、許容される移動手段(DRIVE、WALK)を指定します。
  • usage - ナビゲーション ポイントでサポートされている到着ユースケース(PICKUP、DROPOFF、PARKING など)を指定する新しいフィールド。

建物の輪郭

destination に関連付けられた建物の輪郭を取得するには、建物を表す destination 内の placeView オブジェクトの displayPolygon フィールドを使用します(以前の v3 buildings.building_outlines 配列を置き換えます)。各 placeView について、placeView.structureType フィールドを持つ建物かどうかを確認します。構造タイプが BUILDING の場合、placeView.displayPolygon フィールドからアウトラインを取得できます。placeView には、Geocoding API v3 にはなかった建物の追加フィールドも含まれます。

destination には、次のフィールドに建物を表す placeView オブジェクトを含めることができます。

  • destination.primary - 目的地の主要な場所。
  • destination.containingPlaces - メインの場所を「含む」より大きな場所を保持する繰り返しフィールド。たとえば、メインの場所が subpremise の場合、containingPlaces には通常、建物を表す placeView が格納されます。
  • destination.subDestinations - メインの場所のサブ目的地(建物内の個々のアパートメント ユニットやスイートなど)を保持する繰り返しフィールド。

placeView.displayPolygon の形式は、Geocoding API v3 の建物のアウトライン形式(GeoJSON 形式、RFC 7946 形式を使用)と一致します。

邸宅と庭園

建物の外形と同様に、destination に関連付けられた敷地を取得するには、敷地を表す destination 内の placeView オブジェクトの displayPolygon フィールドを使用します(以前の v3 grounds 配列を置き換えます)。各 placeView について、placeView.structureType フィールドを持つ敷地ポリゴンかどうかを確認します。構造タイプが GROUNDS の場合、placeView.displayPolygon フィールドからアウトラインを取得できます。placeView には、Geocoding API v3 にはなかった敷地に関する追加のフィールドも含まれます。

destination には、次のフィールドに敷地を表す placeView オブジェクトを含めることができます。

  • destination.primary
  • destination.containingPlaces
  • destination.subDestinations

placeView.displayPolygon の形式は、Geocoding API v3 の敷地外形形式(GeoJSON 形式)と一致します。この形式では、RFC 7946 形式が使用されます。

結果の精度

Geocoding API v3 では、レスポンス ジオメトリの location_type フィールドに結果の精度が示され、一部のクライアントはこれらの値(ROOFTOP、RANGE_INTERPOLATED、GEOMETRIC_CENTER、APPROXIMATE)に基づいて結果をランク付けまたはフィルタしていました。標準の Geocoding API v4 移行では、このフィールドの名前が granularity に変更されます。

Destinations API(v4 SearchDestinations)には、location_type フィールドはありません。代わりに、空間情報は次のように処理されます。

  • クライアントサイドでの手動フィルタリングが不要: 標準のジオコーディングでは、さまざまな粒度で複数の結果が返されますが、SearchDestinations メソッドでは、可能な限り最適化された単一の目的地に解決することで、あいまいさを最小限に抑えます。これにより、クライアントは場所のタイプでフィルタして最適な結果を判断する必要がなくなります。
  • 構造タイプと表示ポリゴンで表される空間情報: 空間の形状と構造は、以下によって示されます。
    • displayPolygon(正確なジオメトリ用)。
    • placeView オブジェクト内の structureType フィールド。
  • 構造タイプのマッピング:
    • POINT、BUILDING、SECTION の structureType は、通常、以前に ROOFTOP と呼ばれていたものに対応します。
    • GROUNDS の structureType は、通常 GEOMETRIC_CENTER に対応します。

フィールド マスクを使用してこれらの機能をリクエストする

SearchDestinations メソッドには、返すフィールドを選択するで説明されているように、フィールド マスクが必要です。フィールド マスクを * に設定すると、すべてのフィールドが返されます。また、受信する特定のフィールドに設定することもできます。たとえば、次の API リクエストでは、目的地の入口、ナビゲーション ポイント、建物の輪郭、敷地を取得するために必要なすべてのフィールドを受け取るようにフィールド マスクを設定しています。

curl -X POST -d '{"place": "places/ChIJG3kh4hq6j4AR_XuFQnV0_t8"}' \
  -H "X-Goog-Api-Key: API_KEY" \
  -H "Content-Type: application/json" \
  -H "X-Goog-FieldMask: destinations.entrances,destinations.navigationPoints,destinations.primary,destinations.containingPlaces,destinations.subDestinations" \
  https://geocode.googleapis.com/v4/geocode/destinations

一般的な移行レシピとコードパターン

Geocoding v3 または Geocoding++ から SearchDestinations に複雑なワークフローを移行する場合は、次のコードレシピを使用して、一般的な空間構造と住所構造を抽出します。

最適な建物のポリゴンを抽出する

場所または目的地の建物の輪郭をレンダリングする場合:

  1. primary の場所に structureType === 'BUILDING' があり、displayPolygon が含まれているかどうかを確認します。
  2. そうでない場合は、containingPlaces を調べて、囲んでいる建物を見つけます(主な目的地が大きな建物のサブ目的地である場合に便利です)。
  3. 囲いのある建物が見つからない場合は、subDestinations を確認して、個々の建物がリストされているかどうかを確認します。
Python コードの例
def get_best_building_polygon(destination):
    primary = destination.get('primary', {})
    if primary.get('structureType') == 'BUILDING' and 'displayPolygon' in primary:
        return primary['displayPolygon']

    # Check containing places for the parent building
    for place in destination.get('containingPlaces', []):
        if place.get('structureType') == 'BUILDING' and 'displayPolygon' in place:
            return place['displayPolygon']

    # Fallback to sub-destinations if available
    for place in destination.get('subDestinations', []):
        if place.get('structureType') == 'BUILDING' and 'displayPolygon' in place:
            return place['displayPolygon']

    return None
Node.js のコード例
function getBestBuildingPolygon(destination) {
    const { primary = {}, containingPlaces = [], subDestinations = [] } = destination;

    if (primary.structureType === 'BUILDING' && primary.displayPolygon) {
        return primary.displayPolygon;
    }

    const parentBuilding = containingPlaces.find(
        p => p.structureType === 'BUILDING' && p.displayPolygon
    );
    if (parentBuilding) {
        return parentBuilding.displayPolygon;
    }

    const subBuilding = subDestinations.find(
        p => p.structureType === 'BUILDING' && p.displayPolygon
    );
    return subBuilding?.displayPolygon || null;
}

敷地の輪郭を抽出する

集合住宅、企業キャンパス、ショッピング センター、公園の境界線が必要な場合:

  1. primary の場所が複合施設全体(structureType === 'GROUNDS')を表す場合は、primary.displayPolygon を使用します。
  2. primary の場所が、より大きな複合施設内にある建物または入り口である場合は、containingPlaces で囲まれた敷地を見つけます。
Python コードの例
def get_grounds_polygon(destination):
    primary = destination.get('primary', {})
    if primary.get('structureType') == 'GROUNDS' and 'displayPolygon' in primary:
        return primary['displayPolygon']

    for place in destination.get('containingPlaces', []):
        if place.get('structureType') == 'GROUNDS' and 'displayPolygon' in place:
            return place['displayPolygon']

    return None
Node.js のコード例
function getGroundsPolygon(destination) {
    const { primary = {}, containingPlaces = [] } = destination;

    if (primary.structureType === 'GROUNDS' && primary.displayPolygon) {
        return primary.displayPolygon;
    }

    const groundsPlace = containingPlaces.find(
        p => p.structureType === 'GROUNDS' && p.displayPolygon
    );
    return groundsPlace?.displayPolygon || null;
}

住所表示とラストマイル到着のランドマークを選択する

ジオコーディング v3 address_descriptor が spatial_relationship 列挙型(WITHIN、BESIDE、BEHIND、NEAR、ACROSS_THE_ROAD、AROUND_THE_CORNER)を返しました。SearchDestinations 内:

  • 未加工の関係列挙型はありません。代わりに、relationalDescription.text を直接使用してください。これには、"Across from Central Park" や "Behind the convention center" など、ローカライズされた表示可能なフレーズが含まれています。"Near " を手動で先頭に追加しないでください。
  • tags を使用して、ユースケースに適したランドマークを選択します。
    • ARRIVAL: 目的地のすぐ隣、向かい、または通りを挟んだ向かいにある、地域密着型のランドマーク(通常は 50 ~ 100 メートル以内)。ドライバーのリアルタイムの到着、宅配便の配達確認、アプリ内の到着カードに最適です。
    • ADDRESS: 周辺地域(通常は 100 ~ 500 メートル以内)で、地域的に有名なランドマーク。顧客向けのチェックアウト、注文の確認、乗車前の目的地の曖昧さ回避に最適です。
    • ランドマークに ADDRESS タグと ARRIVAL タグの両方が付いている場合、そのランドマークは近隣でよく知られており、目的地に隣接しています。
Python コードの例
def get_best_relational_landmark(destination, is_last_mile=True):
    """Select the best landmark based on user context.

    Args:
        destination: Destination object from SearchDestinations.
        is_last_mile: True for arrival and delivery guidance (prefers ARRIVAL tags).
                      False for address display and disambiguation (prefers ADDRESS tags).

    Returns:
        Dict with landmark description, distances, tags, and placeId, or None.
    """
    landmarks = destination.get('landmarks', [])
    if not landmarks:
        return None

    target_tag = 'ARRIVAL' if is_last_mile else 'ADDRESS'

    # Landmarks are ranked by relevance and proximity. Select the first candidate matching the target tag.
    for lm in landmarks:
        tags = lm.get('tags', [])
        if target_tag in tags or ('ARRIVAL' in tags and 'ADDRESS' in tags):
            description = lm.get('relationalDescription', {}).get('text')
            if description:
                return {
                    'description': description,
                    'travelDistanceMeters': lm.get('travelDistanceMeters'),
                    'straightLineDistanceMeters': lm.get('straightLineDistanceMeters'),
                    'tags': tags,
                    'placeId': lm.get('place', {}).get('placeId')
                }

    # Fallback to the first available landmark with a relational description if no tagged match is found
    for lm in landmarks:
        description = lm.get('relationalDescription', {}).get('text')
        if description:
            return {
                'description': description,
                'travelDistanceMeters': lm.get('travelDistanceMeters'),
                'straightLineDistanceMeters': lm.get('straightLineDistanceMeters'),
                'tags': lm.get('tags', []),
                'placeId': lm.get('place', {}).get('placeId')
            }

    return None
Node.js のコード例
/**
 * Select the best landmark based on user context.
 *
 * @param {Object} destination Destination object from SearchDestinations.
 * @param {boolean} [isLastMile=true] True for arrival and delivery guidance
 *        (prefers ARRIVAL tags). False for address display and disambiguation
 *        (prefers ADDRESS tags).
 * @return {Object|null}
 */
function getBestRelationalLandmark(destination, isLastMile = true) {
    const landmarks = destination.landmarks || [];
    if (!landmarks.length) return null;

    const targetTag = isLastMile ? 'ARRIVAL' : 'ADDRESS';

    // Landmarks are ranked by relevance and proximity. Select the first candidate matching the target tag.
    const match = landmarks.find((lm) => {
        const tags = lm.tags || [];
        return (tags.includes(targetTag) || (tags.includes('ARRIVAL') && tags.includes('ADDRESS'))) &&
               lm.relationalDescription?.text;
    }) || landmarks.find((lm) => lm.relationalDescription?.text);

    if (match) {
        return {
            description: match.relationalDescription.text,
            travelDistanceMeters: match.travelDistanceMeters,
            straightLineDistanceMeters: match.straightLineDistanceMeters,
            tags: match.tags || [],
            placeId: match.place?.placeId || null,
        };
    }

    return null;
}

車両のナビゲーション ポイントと優先エントランスへのルート

ラスト ワンマイルのディスパッチと到着のワークフローでは、2 種類の空間アクセス ポイントを組み合わせて使用します。

  • ターンバイターン方式の運転: navigationPoints を使用して、指定された道路の降車ポイントに車両をルーティングします。ナビゲーション ポイントは、近接性と関連性によって事前にランク付けされているため、目的の移動手段('DRIVE' など)と使用タグ('DROPOFF' や 'PICKUP' など)を持つ最初の候補が、最適な車両ウェイポイントになります。その navigationPointToken を Routes API の ComputeRoutes メソッド(Waypoint.navigationPointToken)または Navigation SDK に送信します。道路にスナップされた運転ポイントが存在しない場合は、建物の入り口または主要な重心にフォールバックします。
  • 物理的なドアウェイ アクセス: destinations.entrances を使用して、徒歩の配達員または乗客を建物の入り口に案内します。'PREFERRED' の tags を確認して、直接物理的にアクセスできる可能性が高い入り口を見つけます。入口データが利用できない場合は、歩行者ナビゲーション ポイント('WALK' を含む travelModes)または主要な重心にフォールバックします。
Python コードの例
def get_routing_and_arrival_points(destination, usage_tag=None):
    navigation_points = destination.get('navigationPoints', [])
    entrances = destination.get('entrances', [])
    primary_location = destination.get('primary', {}).get('location')

    # 1. Doorstep / Physical Entrance
    # Prefer PREFERRED entrance -> any entrance -> WALK nav point -> primary location
    preferred_entrance = None
    for ent in entrances:
        if 'PREFERRED' in ent.get('tags', []):
            preferred_entrance = ent
            break
    if not preferred_entrance and entrances:
        preferred_entrance = entrances[0]

    walk_nav_point = None
    for np in navigation_points:
        if 'WALK' in np.get('travelModes', []):
            walk_nav_point = np
            break

    if preferred_entrance:
        doorstep_location = preferred_entrance.get('location')
    elif walk_nav_point:
        doorstep_location = walk_nav_point.get('location')
    else:
        doorstep_location = primary_location

    # 2. Vehicle Routing Waypoint
    # Find a driving navigation point. If usage_tag (such as 'DROPOFF' or 'PICKUP')
    # is specified, prioritize a candidate with that usage tag; otherwise fall back
    # to the first available driving point.
    drive_nav_point = None
    fallback_drive_point = None
    for np in navigation_points:
        if 'DRIVE' in np.get('travelModes', []):
            if usage_tag and usage_tag in np.get('usages', []):
                drive_nav_point = np
                break  # Exact match for desired usage tag
            elif fallback_drive_point is None:
                fallback_drive_point = np  # First driving point as fallback

    if not drive_nav_point:
        drive_nav_point = fallback_drive_point

    if drive_nav_point:
        vehicle_location = drive_nav_point.get('location')
        nav_token = drive_nav_point.get('navigationPointToken')
    elif preferred_entrance:
        vehicle_location = preferred_entrance.get('location')
        nav_token = None
    else:
        vehicle_location = primary_location
        nav_token = None

    return {
        'vehicleRoutingWaypoint': {
            'navigationPointToken': nav_token,
            'location': vehicle_location,
        },
        'doorstepLocation': doorstep_location,
    }
Node.js のコード例
function getRoutingAndArrivalPoints(destination, usageTag = null) {
    const navigationPoints = destination.navigationPoints || [];
    const entrances = destination.entrances || [];
    const primaryLocation = destination.primary?.location || null;

    // 1. Doorstep / Physical Entrance
    const preferredEntrance = entrances.find(ent => ent.tags?.includes('PREFERRED'))
        || entrances[0]
        || null;

    const walkNavPoint = navigationPoints.find(np => np.travelModes?.includes('WALK'))
        || null;

    const doorstepLocation = preferredEntrance?.location
        || walkNavPoint?.location
        || primaryLocation;

    // 2. Vehicle Routing Waypoint
    // Find a driving navigation point. If usageTag (such as 'DROPOFF' or 'PICKUP')
    // is specified, prioritize a candidate with that usage tag; otherwise fall back
    // to the first available driving point.
    const driveNavPoint = (usageTag && navigationPoints.find(np => np.travelModes?.includes('DRIVE') && np.usages?.includes(usageTag)))
        || navigationPoints.find(np => np.travelModes?.includes('DRIVE'))
        || null;

    let vehicleLocation = primaryLocation;
    let navToken = null;
    if (driveNavPoint) {
        vehicleLocation = driveNavPoint.location;
        navToken = driveNavPoint.navigationPointToken;
    } else if (preferredEntrance) {
        vehicleLocation = preferredEntrance.location;
    }

    return {
        vehicleRoutingWaypoint: {
            navigationPointToken: navToken,
            location: vehicleLocation,
        },
        doorstepLocation: doorstepLocation,
    };
}

セキュリティ上の考慮事項

Geocoding API v4 は、サーバー間 API として設計されています。JavaScript ユーザーが v3 から v4 に直接移行する方法はありません。API キーを使用してクライアントサイドの JavaScript(ブラウザなど)から v4 メソッドを直接呼び出すと、API キーが盗難や不正使用のリスクにさらされます。

HTTP リファラー制限は有用ですが、リクエストの Referer ヘッダーを偽造する攻撃者によって簡単にバイパスされる可能性があるため、ウェブサービス エンドポイントの保護としては不十分です。

Geocoding API v4 は、独自のバックエンド サーバーから使用することをおすすめします。クライアント アプリケーションは、この中間サーバーにリクエストを送信する必要があります。中間サーバーは、保護された API キー(環境変数や Secret Manager に保存されているキーなど)を使用して Google API を安全に呼び出します。これにより、API キーがフロントエンド コードで公開されることがなくなります。

クライアントサイドのニーズに対応する代替手段

ジオコーディングを必要とするクライアント側のニーズがある場合は、既存のクライアント側ソリューションのいずれかを使用することを検討してください。