Migracja z interfejsu Geocoding API w wersji 3 do wersji 4

Deweloperzy z Europejskiego Obszaru Gospodarczego (EOG)

Geocoding API w wersji 4 wprowadza kilka nowych metod, które zastępują funkcje interfejsu API w wersji 3. Z tego przewodnika dowiesz się, jak przenieść aplikację, aby korzystała z nowych metod w wersji 4.

Możesz używać istniejących kluczy interfejsu API z nowymi metodami w wersji 4. Jeśli jednak masz prośbę o zwiększenie limitu w wersji 3 interfejsu API, musisz poprosić o zwiększenie limitu w nowych interfejsach API w wersji 4.

Migracja z geokodowania bezpośredniego w wersji 3

Jeśli do geokodowania adresów używasz geokodowania w wersji 3, przejdź na metodę geokodowania adresu w wersji 4, która akceptuje żądanie GET.

W interfejsie API w wersji 4 zmieniono nazwy, strukturę i obsługę kilku parametrów. Zdecydowanie zalecamy użycie maski pola, aby określić pola, które mają zostać zwrócone w odpowiedzi.

Zmiany parametrów żądania

Parametr v3 Parametr v4 Uwagi
address, components address Nieustrukturyzowany adres (v3 address) jest teraz przekazywany w ścieżce adresu URL. Komponenty uporządkowanego adresu (v3 components) można przekazywać jako parametry zapytania address.*. Zobacz Odtwarzanie filtrów komponentów w wersji 3.
bounds locationBias.rectangle Zmieniono nazwę; struktura została zmieniona na obiekt.
language languageCode Zmieniono nazwę. Jeśli zostanie pominięty, wersja 3 używa nagłówka Accept-Language lub domyślnie en, a wersja 4 domyślnie używa lokalnego języka i skryptu lokalizacji.
region regionCode Zmieniono nazwę. Jeśli zostanie pominięty, w wersji 3 domyślnie przyjmuje wartość us, a w wersji 4 nie ma wartości domyślnej.
extra_computations Usunięto Zastąpiona przez metodę SearchDestinations.

Zmiany w polu odpowiedzi

Pole w wersji 3 Pole v4 Uwagi
status, error_message Usunięto Wersja 4 używa kodów stanu HTTP i treści błędów.
results.address_components.long_name/results.address_components.short_name results.addressComponents.longText/results.addressComponents.shortText Zmieniono nazwę.
results.geometry.location_type results.granularity Zmieniono nazwę.
results.geometry.location results.location Nazwy pól: lat/lng –> latitude/longitude.
results.geometry.viewport results.viewport Nazwy pól: northeast/southwest –> high/low.
results.postcode_localities results.postalCodeLocalities Zmieniono nazwę. Teraz zwracane dla co najmniej 1 miejscowości (wersja 3 wymaga >1).
results.partial_match Usunięto
Nowość results.addressComponents.languageCode Język konkretnego komponentu adresu.
Nowość results.bounds Jawne granice przy użyciu high/low.
Nowość results.place Nazwa zasobu miejsca.
Nowość results.postalAddress Uporządkowany obiekt PostalAddress.

Odtwarzanie filtrów komponentów w wersji 3

Geokodowanie bezpośrednie w Geocoding v3 zawierało parametr components, który umożliwiał twarde filtrowanie wyników dla określonych komponentów (np. components=country:US). Geokodowanie bezpośrednie w wersji 4 nie obsługuje tego typu twardego filtrowania w parametrach żądania. W wersji 4 możesz podać informacje o adresie jako pojedynczy nieuporządkowany ciąg znaków w ścieżce lub jako uporządkowane parametry zapytania, takie jak address.addressLines, address.locality, address.administrativeArea, address.postalCode i address.regionCode. Parametry uporządkowane nie działają jako filtry bezwzględne. Zamiast tego wszystkie podane komponenty są łączone w pełny adres, który interfejs API próbuje zakodować geograficznie. Interfejs API wyszukuje najlepsze dopasowanie dla całego adresu we wszystkich komponentach. Podanie komponentów w uporządkowany sposób może pomóc interfejsowi API lepiej zrozumieć intencję, zwłaszcza gdy informacje o adresie są zbierane z oddzielnych pól formularza. Może to pomóc interfejsowi API w obsłudze drobnych literówek lub niejednoznaczności w poszczególnych komponentach, ponieważ typ informacji w każdym polu jest jasny.

Aby uzyskać działanie podobne do filtrów komponentów twardych w wersji 3, musisz zaimplementować filtrowanie po stronie klienta w tablicy results zwracanej przez interfejs API w wersji 4 na podstawie obiektów postalAddress i addressComponents w odpowiedzi.

W tabeli poniżej znajdziesz najlepsze dopasowanie filtrów components w wersji 3 do pól postalAddress w wersji 4:

filtr komponentów w wersji 3 Pole odpowiedzi v4
country postalAddress.regionCode
postal_code postalAddress.postalCode
administrative_area postalAddress.administrativeArea lub addressComponents

Przykłady filtrowania po stronie klienta

Poniższe przykłady pokazują, jak filtrować wyniki, aby uzyskać zachowanie podobne do filtrowania komponentów w wersji 3 w przypadku obsługiwanych pól: kraj, region i kod pocztowy. Nie zalecamy filtrowania według innych pól, ponieważ nie ma wiarygodnych kryteriów filtrowania.

Filtruj według kraju

Dopasuj parametr address.regionCode z żądania do parametru postalAddress.regionCode w każdym wyniku. Pamiętaj, że chociaż interfejs API akceptuje w żądaniu kody regionów zapisane małymi literami, w odpowiedzi zawsze zwraca je zapisane wielkimi literami, dlatego przed porównaniem musisz znormalizować dane wejściowe do wielkich liter.

Przykładowy kod w Pythonie
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')
Przykładowy kod w 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');
Filtruj według regionu

Dopasuj parametr address.administrativeArea z żądania do parametru postalAddress.administrativeArea w każdym wyniku. Podobnie jak w przypadku kodów krajów, przed porównaniem należy znormalizować dane wejściowe, aby były zapisane wielkimi literami. Jest to wiarygodne tylko wtedy, gdy parametr administrativeArea w żądaniu jest podany ze standardowym 2-literowym skrótem. Wartość postalAddress.administrativeArea w odpowiedzi może nie odpowiadać bezpośrednio sufiksom kodów ISO 3166-2 z kilku powodów. Po pierwsze, w niektórych obszarach podział odpowiadający kodowi ISO 3166-2 nie jest częścią standardowej reprezentacji adresów pocztowych. Na przykład w Hiszpanii region poziomu 1 (np. „CN” dla Wysp Kanaryjskich) może być obecny w addressComponents, ale postalAddress.administrativeArea może zawierać region poziomu 2 (np. „Santa Cruz de Tenerife”). Po drugie, w niektórych obszarach skrót nazwy podregionu nie jest powszechnie używany i jest reprezentowany w postalAddress.administrativeArea dłuższą nazwą (z podobnych powodów addressComponents.shortText dla komponentu adresu odpowiadającego podregionowi może nie pasować do sufiksu kodu ISO 3166-2 podregionu). W niektórych przypadkach podział może być też reprezentowany w komponencie adresu dla administrative_area_level_n, gdzie n jest większe niż 1. Aby uzyskać najbardziej wyczerpujące wyniki, sprawdź, czy występuje dopasowanie zarówno w postalAddress.administrativeArea, jak i w dowolnym addressComponents z typem administrative_area_level_n (np. administrative_area_level_1).

Przykładowy kod w Pythonie
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')
Przykładowy kod w 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');
Filtrowanie według kodu pocztowego

Dopasuj parametr address.postalCode z żądania do parametru postalAddress.postalCode w każdym wyniku. Przed porównaniem musisz znormalizować zarówno wejściowe, jak i wynikowe kody pocztowe. Logika normalizacji zależy w dużej mierze od regionu. Podstawowe podejście polega na usunięciu spacji i łączników oraz ujednoliceniu wielkości liter.

W przypadku prefiksów kodów pocztowych (np. „L2” w Wielkiej Brytanii) lub sufiksów (np. „+4” w amerykańskich kodach pocztowych) może być konieczna bardziej zaawansowana normalizacja. Wymagana logika normalizacji będzie się różnić w zależności od kraju i formatów kodów pocztowych. Może być konieczne dostosowanie podanych funkcji normalizacji lub wdrożenie bardziej zaawansowanej logiki dla regionów, na które kierujesz reklamy.

Podany przykład obsługuje kody pocztowe w USA i umożliwia dopasowanie na podstawie 5-cyfrowego kodu, nawet jeśli podany lub zwrócony jest kod ZIP+4.

Przykładowy kod w Pythonie (dotyczący kodów pocztowych w USA)
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')
Przykładowy kod w Node.js (dotyczący kodów pocztowych w USA)
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');

Migracja z odwrotnego geokodowania w wersji 3

Jeśli używasz odwrotnego geokodowania w wersji 3 do przekształcania współrzędnych w adresy, przejdź na metodę odwrotnego geokodowania lokalizacji w wersji 4, która akceptuje żądanie GET.

W interfejsie API w wersji 4 zmieniono nazwy, strukturę i obsługę kilku parametrów. Zdecydowanie zalecamy użycie maski pola, aby określić pola, które mają zostać zwrócone w odpowiedzi.

Zmiany parametrów żądania

Parametr v3 Parametr v4 Uwagi
language languageCode Zmieniono nazwę. Jeśli zostanie pominięty, wersja 3 używa nagłówka Accept-Language lub domyślnie en, a wersja 4 domyślnie używa lokalnego języka i skryptu lokalizacji.
region regionCode Zmieniono nazwę. Jeśli zostanie pominięty, w wersji 3 domyślnie przyjmuje wartość us, a w wersji 4 nie ma wartości domyślnej.
result_type types Zmieniono nazwę; używa powtarzających się parametrów zapytania.
location_type granularity Zmieniono nazwę; używa powtarzających się parametrów zapytania.
extra_computations Usunięto Zastąpiona przez metodę SearchDestinations.

Zmiany w polu odpowiedzi

Pole w wersji 3 Pole v4 Uwagi
status, error_message Usunięto Wersja 4 używa kodów stanu HTTP i treści błędów.
results.address_components.long_name/results.address_components.short_name results.addressComponents.longText/results.addressComponents.shortText Zmieniono nazwę.
results.geometry.location_type results.granularity Zmieniono nazwę.
results.geometry.location results.location Nazwy pól: lat/lng –> latitude/longitude.
results.geometry.viewport results.viewport Nazwy pól: northeast/southwest –> high/low.
Nowość results.addressComponents.languageCode Język konkretnego komponentu adresu.
Nowość results.bounds Jawne granice przy użyciu high/low.
Nowość results.place Nazwa zasobu miejsca.
Nowość results.postalAddress Uporządkowany obiekt PostalAddress.

Migracja z deskryptorów adresów w wersji 3

W interfejsie Geocoding API v3 przekazanie extra_computations=ADDRESS_DESCRIPTORS zwracało obiekt address_descriptor zawierający landmarks[] i areas[]. W Geocoding API w wersji 4 tę funkcję zastępuje metoda SearchDestinations (POST /v4/geocode/destinations), która zwraca bogaty kontekst przestrzenny bezpośrednio w każdym obiekcie Destination.

W tabeli poniżej znajdziesz mapowanie starszych pól address_descriptor w wersji 3 na ich odpowiedniki w wersji 4 (SearchDestinations):

Pole address_descriptor w wersji 3 Pole SearchDestinations w wersji 4 Uwagi dotyczące migracji
landmarks[] destinations[].landmarks[] Poproś o destinations.landmarks w X-Goog-FieldMask.
landmarks[].place_id landmarks[].place.placeId Są opakowane w obiekt place (PlaceView).
landmarks[].display_name landmarks[].place.displayName Zlokalizowany tekst (text i languageCode).
landmarks[].types landmarks[].place.types Tablica ciągów znaków typów miejsc.
landmarks[].spatial_relationship landmarks[].relationalDescription Zamiast nieprzetworzonego typu wyliczeniowego (ACROSS_THE_ROAD, AROUND_THE_CORNER) wersja 4 zwraca zlokalizowane, zrozumiałe dla człowieka wyrażenie (np. "Across from Central Park").
landmarks[].straight_line_distance_meters landmarks[].straightLineDistanceMeters Zmieniono nazwę na lower camelCase.
landmarks[].travel_distance_meters landmarks[].travelDistanceMeters Zmieniono nazwę na lower camelCase.
areas[] (typ wyliczeniowy containment) destinations[].containingPlaces[] i subDestinations[] Najbliższy dostępny odpowiednik hierarchii strukturalnej: otaczające kompleksy, kampusy, centra handlowe i budynki są zwracane jako obiekty PlaceView w polach containingPlaces[] i subDestinations[] (z polem structureType ustawionym na GROUNDS lub BUILDING i opcjonalnymi konturami displayPolygon). Pamiętaj, że nie ma bezpośredniego odpowiednika 1:1 dla obszarów zbliżonych do dzielnicy/okręgu ani dla typu wyliczeniowego containment w wersji 3 (NEAR, WITHIN, OUTSKIRTS).

Migracja z geokodowania miejsc w wersji 3

Jeśli używasz place_id, aby uzyskać adres dla konkretnego identyfikatora miejsca za pomocą Geocoding v3, musisz przejść na metodę Place Geocoding w wersji 4, która akceptuje żądanie GET.

W interfejsie API w wersji 4 zmieniono nazwy, strukturę i obsługę kilku parametrów. Zdecydowanie zalecamy użycie maski pola, aby określić pola, które mają zostać zwrócone w odpowiedzi.

Zmiany parametrów żądania

Parametr v3 Parametr v4 Uwagi
place_id Pole place w proto żądania Identyfikator miejsca jest teraz podawany jako parametr ścieżki places/{place}, na przykład: https://geocode.googleapis.com/v4/geocode/places/ChIJj61dQgK6j4AR4GeTYWZsKWw. Jest ono mapowane na pole miejsca w podstawowym żądaniu.
language languageCode Zmieniono nazwę. Jeśli zostanie pominięty, wersja 3 używa nagłówka Accept-Language lub domyślnie en, a wersja 4 domyślnie używa lokalnego języka i skryptu lokalizacji.
region regionCode Zmieniono nazwę. Jeśli zostanie pominięty, w wersji 3 domyślnie przyjmuje wartość us, a w wersji 4 nie ma wartości domyślnej.

Zmiany w polu odpowiedzi

Pole w wersji 3 Pole v4 Uwagi
status, error_message Usunięto Wersja 4 używa kodów stanu HTTP i treści błędów.
results (root) Wersja 4 zwraca pojedynczy obiekt wynikowy, a nie tablicę results.
results.address_components.long_name/results.address_components.short_name addressComponents.longText/addressComponents.shortText Zmieniono nazwę.
results.geometry.location_type granularity Zmieniono nazwę.
results.geometry.location location Nazwy pól: lat/lng –> latitude/longitude.
results.geometry.viewport viewport Nazwy pól: northeast/southwest –> high/low.
results.postcode_localities postalCodeLocalities Zmieniono nazwę. Teraz zwracane dla co najmniej 1 miejscowości (wersja 3 wymaga >1).
Nowość addressComponents.languageCode Język konkretnego komponentu adresu.
Nowość bounds Jawne granice przy użyciu high/low.
Nowość place Nazwa zasobu miejsca.
Nowość postalAddress Uporządkowany obiekt PostalAddress.

Migracja z geokodowania hiperlokalnych danych do miejsc docelowych

Te funkcje interfejsu Geocoding API w wersji 3 są zastępowane przez metodę SearchDestinations interfejsu Geocoding API w wersji 4:

  • Wejścia
  • Punkty nawigacyjne
  • Kontury budynków
  • Tereny posiadłości

Jeśli do korzystania z powyższych funkcji używasz interfejsu Geocoding API w wersji 3, zapoznaj się z tym dokumentem, aby dowiedzieć się, jak zamiast tego używać metody SearchDestinations. W tym dokumencie wyjaśniamy, gdzie w odpowiedzi SearchDestinations można znaleźć te funkcje, oraz opisujemy różnice w sposobie ich reprezentowania w odpowiedziach interfejsu API między interfejsem Geocoding API w wersji 3 a metodą SearchDestinations interfejsu Geocoding API w wersji 4.

Wejścia

Aby uzyskać wejścia powiązane z destination, użyj pola destination.entrances.

Każdy element entrance w destination.entrances ma te pola (zastępujące starszy schemat buildings.entrances w wersji 3):

  • displayName – nowe opcjonalne pole, które zawiera zrozumiałą dla człowieka nazwę wejścia, np. "Gate B".
  • location – lokalizacja typu LatLng korzystająca z latitude i longitude (zastępuje lat/lng w wersji 3).
  • tags – taki sam jak pole tags z wejść Geocoding API w wersji 3 (np. PREFERRED).
  • place – nazwa zasobu miejsca (np. places/ChIJ...), która zastępuje pole building_place_id z interfejsu Geocoding API w wersji 3. W wersji 4 to miejsce może reprezentować dowolną strukturę miejsca docelowego (budynek, kampus lub park), a nie tylko budynek.

Aby uzyskać punkty nawigacyjne powiązane z destination, użyj pola destination.navigationPoints.

Każdy element navigationPoint w destination.navigationPoints ma te pola (zastępujące starszy schemat navigation_points w wersji 3):

  • navigationPointToken – zaszyfrowany ciąg tokena używany do kierowania do tego konkretnego punktu nawigacyjnego w metodzie ComputeRoutes interfejsu Routes API (Waypoint.navigationPointToken). Zobacz Wyznaczanie trasy za pomocą tokenów punktów nawigacyjnych.
  • displayName – nowe opcjonalne pole, które zawiera zrozumiałą dla człowieka nazwę punktu nawigacyjnego, np. "5th Ave".
  • location – lokalizacja typu LatLng, która korzysta z latitude i longitude.
  • travelModes – podobne do pola restricted_travel_modes z Geocoding API w wersji 3, z tą różnicą, że w wersji 4 określa akceptowalne środki transportu (DRIVE, WALK), a nie ograniczone środki transportu.
  • usage – nowe pole określające obsługiwane przypadki użycia punktu nawigacyjnego (np. PICKUP, DROPOFF lub PARKING).

Kontury budynków

Aby uzyskać obrysy budynków powiązane z destination, użyj pola displayPolygon obiektów placeView w destination, które reprezentują budynki (zastępując starszą tablicę buildings.building_outlines w wersji 3). W przypadku każdego elementu placeView sprawdź, czy jest to budynek z polem placeView.structureType. Jeśli typ struktury to BUILDING, możesz uzyskać konspekt z pola placeView.displayPolygon. placeView będzie też zawierać dodatkowe pola dotyczące budynku, których nie było w interfejsie Geocoding API w wersji 3.

Obiekt destination może zawierać obiekt placeView, który reprezentuje budynek w tych polach:

  • destination.primary – główne miejsce w miejscu docelowym.
  • destination.containingPlaces – pole powtarzane, które zawiera większe miejsca „zawierające” miejsce główne. Jeśli na przykład głównym miejscem jest subpremise, containingPlaces zwykle zawiera placeView reprezentujący budynek.
  • destination.subDestinations – pole powtarzane, które zawiera miejsca podrzędne miejsca głównego (np. poszczególne mieszkania lub apartamenty w budynku).

Zwróć uwagę, że format placeView.displayPolygon odpowiada formatowi obrysu budynku w interfejsie Geocoding API w wersji 3, czyli formatowi GeoJSON, który używa formatu RFC 7946.

Tereny posiadłości

Podobnie jak w przypadku obrysów budynków, aby uzyskać tereny powiązane z destination, użyj pola displayPolygon obiektów placeView w destination, które reprezentują tereny (zastępując starszą tablicę grounds w wersji 3). Sprawdź, czy każdy element placeView jest wielokątem terenu z polem placeView.structureType. Jeśli typ struktury to GROUNDS, konspekt możesz pobrać z pola placeView.displayPolygon. placeView będzie też zawierać dodatkowe pola dotyczące terenów, których nie było w interfejsie Geocoding API w wersji 3.

Obiekt destination może zawierać obiekt placeView, który reprezentuje teren w tych polach:

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

Zwróć uwagę, że format placeView.displayPolygon odpowiada formatowi konturu terenu w interfejsie Geocoding API w wersji 3, czyli formatowi GeoJSON, który korzysta z formatu RFC 7946.

Precyzja wyników

W Geocoding API w wersji 3 pole location_type w geometrii odpowiedzi wskazywało dokładność wyników, a niektórzy klienci oceniali lub filtrowali wyniki na podstawie tych wartości (ROOFTOP, RANGE_INTERPOLATED, GEOMETRIC_CENTER i APPROXIMATE). W przypadku standardowych migracji do Geocoding API w wersji 4 nazwa tego pola została zmieniona na granularity.

W interfejsie Destinations API (wersja 4 SearchDestinations) nie ma pola location_type. Zamiast tego informacje przestrzenne są przetwarzane w inny sposób:

  • Brak konieczności ręcznego filtrowania po stronie klienta: standardowe geokodowanie zapewnia wiele wyników o różnym stopniu szczegółowości, natomiast metoda SearchDestinations minimalizuje niejednoznaczność, zwracając w miarę możliwości pojedyncze, zoptymalizowane miejsce docelowe. Dzięki temu klienci nie muszą filtrować wyników według typu lokalizacji, aby określić, który wynik jest najlepszy.
  • Informacje przestrzenne reprezentowane przez typ struktury i wielokąty wyświetlania: geometria przestrzenna i struktura są wskazywane przez:
    • displayPolygon (dokładna geometria).
    • Pole structureType w obiekcie placeView.
  • Mapowanie typu struktury:
    • structureType o wartości POINT, BUILDING lub SECTION zazwyczaj odpowiada temu, co wcześniej nazywano ROOFTOP.
    • Wartość structureType parametru GROUNDS odpowiada zwykle GEOMETRIC_CENTER.

Używanie maski pola do wysyłania żądań dotyczących tych funkcji

Metoda SearchDestinations wymaga maski pola, jak wyjaśniono w artykule Wybieranie pól do zwrócenia. Aby zwrócić wszystkie pola, możesz ustawić maskę pola na *. Możesz też ustawić ją na konkretne pola, które chcesz otrzymać. Na przykład to żądanie do interfejsu API ustawia maskę pola, aby otrzymywać wszystkie pola wymagane do uzyskania wejść, punktów nawigacyjnych, obrysów budynków i terenów miejsca docelowego:

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

Typowe przepisy na migrację i wzorce kodu

Podczas migracji złożonych przepływów pracy z Geocoding v3 lub Geocoding++ do SearchDestinations użyj tych przepisów na kod, aby wyodrębnić typowe struktury przestrzenne i adresowe.

Wyodrębnij najlepszy wielokąt budynku

Jeśli chcesz wyrenderować obrys budynku dla lokalizacji lub miejsca docelowego:

  1. Sprawdź, czy miejsce primary ma structureType === 'BUILDING' i zawiera displayPolygon.
  2. Jeśli nie, sprawdź containingPlaces, aby znaleźć budynek, w którym znajduje się miejsce docelowe (przydatne, gdy główne miejsce docelowe jest podrzędnym miejscem docelowym większego budynku).
  3. Jeśli nie znajdziesz budynku nadrzędnego, sprawdź subDestinations, aby zobaczyć, czy poszczególne budynki są wymienione.
Przykładowy kod w Pythonie
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
Przykładowy kod w 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;
}

Wyodrębnij kontur terenu

Jeśli potrzebujesz granicy kompleksu apartamentów, kampusu firmowego, centrum handlowego lub parku:

  1. Jeśli miejsce primary reprezentuje cały kompleks (structureType === 'GROUNDS'), użyj primary.displayPolygon.
  2. Jeśli miejsce primary jest budynkiem lub wejściem znajdującym się w większym kompleksie, znajdź otaczający go teren w containingPlaces.
Przykładowy kod w Pythonie
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
Przykładowy kod w 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;
}

Wybieranie punktów orientacyjnych do wyświetlania adresu i ostatniego etapu podróży

Geocoding v3 address_descriptor zwrócił typ wyliczeniowy spatial_relationship (WITHIN, BESIDE, BEHIND, NEAR, ACROSS_THE_ROAD, AROUND_THE_CORNER). W SearchDestinations:

  • Brak nieprzetworzonego typu wyliczeniowego relacji. Zamiast tego użyj bezpośrednio relationalDescription.text. Zawiera zlokalizowane, gotowe do wyświetlenia wyrażenia, takie jak "Across from Central Park" lub "Behind the convention center". Nie dodawaj ręcznie "Near " na początku.
  • Użyj tags, aby wybrać odpowiedni punkt orientacyjny dla swojego przypadku użycia:
    • ARRIVAL: hiperlokalne punkty orientacyjne położone bezpośrednio obok miejsca docelowego, naprzeciwko niego lub po drugiej stronie ulicy (zwykle w odległości 50–100 metrów). Najlepiej sprawdza się w przypadku informacji o przyjeździe kierowcy w czasie rzeczywistym, potwierdzenia dostawy przez kuriera lub kart przyjazdu w aplikacji.
    • ADDRESS: lokalne punkty orientacyjne w pobliżu (zwykle w odległości 100–500 metrów). Najlepiej sprawdza się w przypadku płatności, sprawdzania zamówienia lub uściślania miejsca docelowego przed podróżą.
    • Jeśli punkt orientacyjny ma zarówno tag ADDRESS, jak i ARRIVAL, oznacza to, że jest dobrze znany w okolicy i znajduje się bezpośrednio obok miejsca docelowego.
Przykładowy kod w Pythonie
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
Przykładowy kod w 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;
}

wyznaczanie trasy do punktów nawigacji pojazdu i preferowanych wejść;

Przepływy pracy związane z wysyłką i przybyciem na ostatnim odcinku łączą 2 uzupełniające się typy przestrzennych punktów dostępu:

  • Szczegółowe wskazówki dojazdu: kieruj pojazdy do wyznaczonych punktów odbioru na drodze za pomocą navigationPoints. Punkty nawigacyjne są wstępnie uszeregowane według bliskości i trafności, więc pierwszy kandydat z wybranym trybem podróży (np. 'DRIVE') i tagiem użytkowania (np. 'DROPOFF' lub 'PICKUP') zapewnia optymalny punkt na trasie pojazdu. Wyślij jego navigationPointToken do metody ComputeRoutes interfejsu Routes API (Waypoint.navigationPointToken) lub do pakietu Navigation SDK. Jeśli nie ma punktu dojazdu przyciągniętego do drogi, użyj wejścia do budynku lub głównego środka ciężkości.
  • Dostęp do drzwi wejściowych: poprowadź pieszego kuriera lub pasażera do wejścia do budynku za pomocą destinations.entrances. Sprawdź tags dla 'PREFERRED', aby znaleźć wejścia, które prawdopodobnie zapewniają bezpośredni dostęp fizyczny. Jeśli nie ma danych o wejściu, użyj punktu nawigacji pieszej (travelModes, w tym 'WALK') lub głównego środka ciężkości.
Przykładowy kod w Pythonie
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,
    }
Przykładowy kod w 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,
    };
}

Bezpieczeństwo

Interfejs Geocoding API w wersji 4 został zaprojektowany jako interfejs API między serwerami. Nie ma bezpośredniej ścieżki migracji dla użytkowników JavaScriptu z wersji 3 do wersji 4. Wywoływanie metod v4 bezpośrednio z kodu JavaScript po stronie klienta (np. w przeglądarce) przy użyciu klucza interfejsu API naraża ten klucz na kradzież i niewłaściwe użycie.

Ograniczenia dotyczące stron odsyłających HTTP, choć przydatne, nie zapewniają wystarczającej ochrony punktów końcowych usług internetowych, ponieważ mogą zostać łatwo pominięte przez atakujących, którzy sfałszują nagłówek Referer w swoich żądaniach.

Zalecanym sposobem korzystania z interfejsu Geocoding API w wersji 4 jest używanie go z własnego serwera backendu. Aplikacja kliencka powinna wysyłać żądania do tego serwera pośredniczącego, który następnie bezpiecznie wywołuje interfejs API Google za pomocą chronionego klucza interfejsu API (np. klucza przechowywanego w zmiennej środowiskowej lub Secret Managerze). Dzięki temu klucz interfejsu API nigdy nie zostanie ujawniony w kodzie frontendu.

Alternatywne rozwiązania po stronie klienta

Jeśli masz potrzeby po stronie klienta, które wymagają geokodowania, rozważ użycie jednego z istniejących rozwiązań po stronie klienta: