В Geocoding API версии 4 появилось несколько новых методов, которые заменяют функции версии 3. В этом руководстве рассказывается, как перенести приложение на новые методы версии 4.
Вы можете использовать существующие ключи API с новыми методами v4. Однако если вы запрашивали увеличение квоты для версии 3 API, вам нужно будет запросить его и для версии 4.
Переход с прямого геокодирования версии 3
Если вы используете v3 Geocoding для геокодирования адресов, перейдите на метод Geocode an address v4, который принимает GET-запрос.
В API v4 изменены названия, структура и поддержка нескольких параметров. Мы настоятельно рекомендуем использовать маску полей, чтобы указать, какие поля должны возвращаться в ответе.
Изменения параметров запроса
| Параметр v3 | Параметр v4 | Примечания |
|---|---|---|
address, components |
address |
Неструктурированный адрес (v3 address) теперь передается в пути URL. Структурированные компоненты адреса (v3 components) можно передавать как параметры запроса address.*. Подробнее о том, как воспроизвести фильтры компонентов версии 3… |
bounds |
locationBias.rectangle |
Переименовано; структура изменена на объект. |
language |
languageCode |
Объект переименован. Если этот параметр не указан, в версии 3 используется заголовок Accept-Language или значение по умолчанию en, а в версии 4 – местный язык и письменность. |
region |
regionCode |
Объект переименован. Если он не указан, в v3 по умолчанию используется us, а в v4 значения по умолчанию нет. |
extra_computations |
Удалено | Заменен методом SearchDestinations. |
Изменения в поле ответа
| Поле v3 | Поле v4 | Примечания |
|---|---|---|
status, error_message |
Удалено | В версии 4 используются коды статуса 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 |
Объект переименован. Теперь возвращается для одного или нескольких населенных пунктов (в версии 3 требовалось больше одного). |
results.partial_match |
Удалено | |
| Новое | results.addressComponents.languageCode |
Язык определенного компонента адреса. |
| Новое | results.bounds |
Явные границы с использованием high/low. |
| Новое | results.place |
Название ресурса для места. |
| Новое | results.postalAddress |
Структурированный объект PostalAddress. |
Воспроизвести фильтры компонентов версии 3
Прямое геокодирование в Geocoding v3 включало параметр components, который позволял выполнять жесткую фильтрацию результатов для определенных компонентов (например, components=country:US). Прямое геокодирование в v4 не поддерживает этот тип жесткой фильтрации в параметрах запроса. В версии 4 вы можете указать адрес в виде одной неструктурированной строки в пути или в виде структурированных параметров запроса, таких как address.addressLines, address.locality, address.administrativeArea, address.postalCode и address.regionCode.
Структурированные параметры не действуют как жесткие фильтры. Вместо этого все предоставленные компоненты объединяются в полный адрес, который API попытается геокодировать. API ищет наилучшее совпадение для всего адреса, указанного во всех компонентах. Если вы предоставите компоненты в структурированном виде, API будет проще понять намерение, особенно если информация об адресе собирается из отдельных полей формы. Это может помочь API обрабатывать незначительные опечатки или двусмысленности в каждом компоненте, поскольку тип информации в каждом поле ясен.
Чтобы добиться поведения, аналогичного строгим фильтрам компонентов в версии 3, необходимо реализовать фильтрацию на стороне клиента для массива results, возвращаемого API версии 4, на основе объектов postalAddress и addressComponents в ответе.
В таблице ниже показано, как фильтры components версии 3 соотносятся с полями postalAddress версии 4.
| Фильтр компонентов v3 | Поле ответа в версии 4 |
|---|---|
country |
postalAddress.regionCode |
postal_code |
postalAddress.postalCode |
administrative_area |
postalAddress.administrativeArea или addressComponents |
Примеры клиентской фильтрации
В примерах ниже показано, как фильтровать результаты, чтобы получить поведение, аналогичное фильтрации компонентов в версии 3 для поддерживаемых полей: страны, административного района и почтового индекса. Фильтровать по другим полям не рекомендуется, поскольку надежных критериев фильтрации не существует.
Фильтр по странам
Сопоставьте 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. Значение postalAddress.administrativeArea в ответе может не совпадать с суффиксами кодов ISO 3166-2 по нескольким причинам. Во-первых, в некоторых регионах административная единица, соответствующая коду ISO 3166-2, не является частью стандартного представления почтовых адресов. Например, в Испании административный район первого уровня (например, "CN" для Канарских островов) может быть указан в поле addressComponents, а в поле postalAddress.administrativeArea может содержаться район второго уровня (например, "Санта-Крус-де-Тенерифе"). Во-вторых, в некоторых регионах сокращение административной единицы не используется, и в postalAddress.administrativeArea она представлена более длинным названием. По аналогичным причинам addressComponents.shortText для компонента адреса, соответствующего административной единице, может не совпадать с суффиксом кода ISO 3166-2 административной единицы. Кроме того, в некоторых случаях административная единица может быть представлена в компоненте адреса для administrative_area_level_n, где n больше 1.
Чтобы получить наиболее полные результаты, проверьте совпадения как в postalAddress.administrativeArea, так и в любом addressComponents с типом administrative_area_level_n (например, administrative_area_level_1).
Пример кода на 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.
Пример кода на 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');
Переход с обратного геокодирования версии 3
Если вы используете обратное геокодирование v3 для преобразования координат в адреса, вам следует перейти на метод обратного геокодирования местоположения v4, который принимает GET-запрос.
В API v4 изменены названия, структура и поддержка нескольких параметров. Мы настоятельно рекомендуем использовать маску полей, чтобы указать, какие поля должны возвращаться в ответе.
Изменения параметров запроса
| Параметр v3 | Параметр v4 | Примечания |
|---|---|---|
language |
languageCode |
Объект переименован. Если этот параметр не указан, в версии 3 используется заголовок Accept-Language или значение по умолчанию en, а в версии 4 – местный язык и письменность. |
region |
regionCode |
Объект переименован. Если он не указан, в v3 по умолчанию используется us, а в v4 значения по умолчанию нет. |
result_type |
types |
Переименован; использует повторяющиеся параметры запроса. |
location_type |
granularity |
Переименован; использует повторяющиеся параметры запроса. |
extra_computations |
Удалено | Заменен методом SearchDestinations. |
Изменения в поле ответа
| Поле v3 | Поле v4 | Примечания |
|---|---|---|
status, error_message |
Удалено | В версии 4 используются коды статуса 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. |
Переход с описаний адресов версии 3
В Geocoding API версии 3 передача extra_computations=ADDRESS_DESCRIPTORS возвращала объект address_descriptor, содержащий landmarks[] и areas[]. В Geocoding API v4 эта возможность заменена методом SearchDestinations (POST /v4/geocode/destinations), который возвращает подробный пространственный контекст непосредственно в каждом объекте Destination.
В таблице ниже показано, как поля address_descriptor устаревшей версии 3 сопоставляются с эквивалентными полями SearchDestinations версии 4.
Поле address_descriptor (версия 3) |
Поле SearchDestinations (версия 4) |
Примечания к переносу |
|---|---|---|
landmarks[] |
destinations[].landmarks[] |
Запросите destinations.landmarks в X-Goog-FieldMask. |
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 |
Вместо необработанного перечисления (ACROSS_THE_ROAD, AROUND_THE_CORNER) версия 4 возвращает локализованную, понятную человеку фразу (например, "Across from Central Park"). |
landmarks[].straight_line_distance_meters |
landmarks[].straightLineDistanceMeters |
Переименовано в lower camelCase. |
landmarks[].travel_distance_meters |
landmarks[].travelDistanceMeters |
Переименовано в lower camelCase. |
areas[] (перечисление containment) |
destinations[].containingPlaces[] и subDestinations[] |
Ближайший доступный эквивалент для структурной иерархии: окружающие комплексы, кампусы, торговые центры и здания возвращаются как структурированные объекты PlaceView в containingPlaces[] и subDestinations[] (с structureType, установленным на GROUNDS или BUILDING, и необязательными контурами displayPolygon). Обратите внимание, что для районов и округов, а также для перечисления containment в версии 3 (NEAR, WITHIN, OUTSKIRTS) нет прямой замены. |
Переход с геокодирования мест в версии 3
Если вы используете place_id, чтобы получить адрес для определенного идентификатора места с помощью Geocoding v3, вам нужно перейти на метод геокодирования мест v4, который принимает GET-запрос.
В API v4 изменены названия, структура и поддержка нескольких параметров. Мы настоятельно рекомендуем использовать маску полей, чтобы указать, какие поля должны возвращаться в ответе.
Изменения параметров запроса
| Параметр v3 | Параметр v4 | Примечания |
|---|---|---|
place_id |
Поле place в прототипе запроса |
Идентификатор места теперь указывается как параметр пути places/{place}, например https://geocode.googleapis.com/v4/geocode/places/ChIJj61dQgK6j4AR4GeTYWZsKWw. Это сопоставляется с полем места в базовом запросе. |
language |
languageCode |
Объект переименован. Если этот параметр не указан, в версии 3 используется заголовок Accept-Language или значение по умолчанию en, а в версии 4 – местный язык и письменность. |
region |
regionCode |
Объект переименован. Если он не указан, в v3 по умолчанию используется us, а в v4 значения по умолчанию нет. |
Изменения в поле ответа
| Поле v3 | Поле v4 | Примечания |
|---|---|---|
status, error_message |
Удалено | В версии 4 используются коды статуса 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 |
Объект переименован. Теперь возвращается для одного или нескольких населенных пунктов (в версии 3 требовалось больше одного). |
| Новое | addressComponents.languageCode |
Язык определенного компонента адреса. |
| Новое | bounds |
Явные границы с использованием high/low. |
| Новое | place |
Название ресурса для места. |
| Новое | postalAddress |
Структурированный объект PostalAddress. |
Переход с геокодирования гиперлокальных данных на Destinations
Следующие функции Geocoding API версии 3 заменяются методом SearchDestinations Geocoding API версии 4:
- Входы
- Точки навигации
- Контуры зданий
- Территория
Если вы использовали Geocoding API версии 3 для указанных выше функций, используйте этот документ, чтобы перейти на метод SearchDestinations.
В этом документе объясняется, где в ответе SearchDestinations найти эти функции и чем они отличаются в ответах Geocoding API версии 3 и метода SearchDestinations Geocoding API версии 4.
Входы
Чтобы получить входы, связанные с destination, используйте поле destination.entrances.
Каждый объект entrance в destination.entrances содержит следующие поля (заменяющие устаревшую схему buildings.entrances версии 3):
displayName– новое необязательное поле, которое содержит понятное название входа, например"Gate B".location– местоположение типаLatLng, использующееlatitudeиlongitude(заменяетlat/lngв версии 3).tags– то же, что и полеtagsиз входов Geocoding API v3 (например,PREFERRED).place– название ресурса места (например,places/ChIJ...), заменяющее полеbuilding_place_idиз Geocoding API версии 3. В версии 4 это место может представлять собой любую структуру назначения (здание, кампус или парк), а не только здание.
Точки навигации
Чтобы получить точки навигации, связанные с destination, используйте поле destination.navigationPoints.
Каждый объект navigationPoint в destination.navigationPoints содержит следующие поля (заменяющие устаревшую схему navigation_points версии 3):
navigationPointToken– зашифрованная строка токена, используемая для маршрутизации к этой конкретной точке навигации в методеComputeRoutesRoutes API (Waypoint.navigationPointToken). Подробнее о маршрутизации с использованием токенов точек навигации…displayName– новое необязательное поле, содержащее понятное название точки навигации, например"5th Ave".location– местоположение типаLatLng, использующееlatitudeиlongitude.travelModes– аналогично полюrestricted_travel_modesиз Geocoding API версии 3, за исключением того, что в версии 4 указываются допустимые способы передвижения (DRIVE,WALK), а не запрещенные.usage– новое поле, в котором указываются поддерживаемые варианты прибытия для точки навигации (например,PICKUP,DROPOFFилиPARKING).
Контуры зданий
Чтобы получить контуры зданий, связанные с destination, используйте поле displayPolygon объектов placeView в destination, которые представляют здания (заменяет устаревший массив buildings.building_outlines из версии 3). Для каждого объекта 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 версии 3, который является форматом GeoJSON, использующим формат RFC 7946.
Территория
Чтобы получить территорию, связанную с объектом destination, используйте поле displayPolygon объектов placeView в destination, которые представляют территорию (заменяет устаревший массив grounds в v3). Для каждого объекта placeView проверьте, является ли он многоугольником территории, с помощью поля placeView.structureType. Если тип структуры – GROUNDS, то контур можно получить из поля placeView.displayPolygon. В placeView также будут дополнительные поля для территорий, которых не было в Geocoding API v3.
Объект destination может содержать объект placeView, который представляет территорию в следующих полях:
destination.primarydestination.containingPlacesdestination.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(для точной геометрии).- Поле
structureTypeв объектеplaceView.
- Сопоставление типов структур:
- Значение
structureType, равноеPOINT,BUILDINGилиSECTION, обычно соответствует тому, что ранее называлосьROOFTOP. structureTypeGROUNDSобычно соответствует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 используйте следующие рецепты кода для извлечения общих пространственных структур и структур адресов.
Извлечь лучший многоугольник здания
Чтобы отрисовать контур здания для местоположения или пункта назначения, выполните следующие действия:
- Проверьте, есть ли в месте
primarystructureType === 'BUILDING'иdisplayPolygon. - Если нет, проверьте
containingPlaces, чтобы найти здание, в котором находится пункт назначения (полезно, если основной пункт назначения является частью более крупного здания). - Если здание не найдено, проверьте
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; }
Извлечь контур территории
Если вам нужно указать границы жилого комплекса, корпоративного кампуса, торгового центра или парка:
- Если место
primaryпредставляет весь комплекс (structureType === 'GROUNDS'), используйтеprimary.displayPolygon. - Если место
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; }
Выбор ориентиров для показа адреса и прибытия на последнюю милю
Geocoding 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; }
Прокладывайте маршруты к точкам навигации и предпочитаемым въездам.
Рабочие процессы отправки и прибытия на последнем этапе доставки сочетают два взаимодополняющих типа пространственных точек доступа:
- Пошаговая навигация. Направляйте транспортные средства к назначенным точкам высадки на дороге с помощью
navigationPoints. Точки навигации предварительно ранжируются по близости и релевантности, поэтому первый кандидат с желаемым режимом поездки (например,'DRIVE') и тегом использования (например,'DROPOFF'или'PICKUP') обеспечивает оптимальную путевую точку транспортного средства. Отправьте егоnavigationPointTokenв методComputeRoutesRoutes API (Waypoint.navigationPointToken) или Navigation SDK. Если точки привязки к дороге нет, используйте вход в здание или основной центроид. - Доступ к дверям. Направьте курьера или пассажира к входу в здание, используя
destinations.entrances. Проверьтеtagsдля'PREFERRED', чтобы найти входы, которые, вероятно, обеспечивают прямой физический доступ. Если данных о входе нет, используйте точку навигации для пешеходов (travelModes, включая'WALK') или основной центроид.
Пример кода на 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 версии 4 предназначен для межсерверного взаимодействия. Прямого пути перехода с версии 3 на версию 4 для пользователей JavaScript нет. Вызов методов v4 непосредственно из клиентского кода JavaScript (например, в браузере) с использованием ключа API подвергает ваш ключ API высокому риску кражи и неправомерного использования.
Ограничения по заголовку HTTP referer полезны, но недостаточны для защиты конечных точек веб-сервисов, поскольку злоумышленники могут легко обойти их, подделав заголовок Referer в своих запросах.
Рекомендуемый подход
Рекомендуемый способ использования Geocoding API версии 4 – с вашего собственного бэкенд-сервера. Ваше клиентское приложение должно отправлять запросы на этот промежуточный сервер, который затем безопасно вызывает Google API, используя защищенный ключ API (например, ключ, хранящийся в переменной среды или диспетчере секретов). Это гарантирует, что ключ API не будет виден в коде интерфейса.
Альтернативные варианты для клиентской стороны
Если вам нужно геокодирование на стороне клиента, используйте одно из существующих решений:
- Сервис Geocoding в Maps JavaScript API. Сервис Geocoding по-прежнему использует серверную часть версии 3 и предназначен для использования в браузере.
- Places UI Kit. Используйте Places UI Kit, включая элементы автозаполнения мест, для элементов пользовательского интерфейса, связанных с адресами.