בגרסה 4 של Geocoding API יש כמה שיטות חדשות שמחליפות את הפונקציונליות של גרסה 3. במדריך הזה מוסבר איך להעביר את האפליקציה לשימוש בשיטות החדשות של גרסה 4.
אתם יכולים להשתמש במפתחות ה-API הקיימים שלכם עם ה-methods החדשות של גרסה 4. עם זאת, אם ביקשתם להגדיל את המכסה בגרסה 3 של ה-API, אתם צריכים לבקש להגדיל את המכסה בממשקי ה-API החדשים בגרסה 4.
מעבר מ-v3 Forward Geocoding
אם אתם משתמשים ב-v3 Geocoding כדי להמיר כתובות לקואורדינטות, אתם צריכים לעבור לשיטה Geocode an address בגרסה 4, שמקבלת בקשת GET.
בגרסה 4 של ה-API יש שינויים בשמות, במבנה ובתמיכה בכמה פרמטרים. מומלץ מאוד להשתמש במסכת שדה כדי לציין את השדות שרוצים להחזיר בתגובה.
בקשה לשינוי פרמטרים
| פרמטר בגרסה 3 | פרמטר v4 | הערות |
|---|---|---|
address, components |
address |
כתובת לא מובנית (גרסה 3 address) מועברת עכשיו בנתיב כתובת ה-URL. אפשר להעביר רכיבי כתובת מובנים (גרסה 3 components) כפרמטרים של שאילתה ב-address.*. איך משחזרים מסנני רכיבים מגרסה 3 |
bounds |
locationBias.rectangle |
השם השתנה, המבנה השתנה לאובייקט. |
language |
languageCode |
השם שונה. אם משמיטים את הפרמטר, בגרסה 3 נעשה שימוש בכותרת Accept-Language או בערך ברירת המחדל en, ואילו בגרסה 4 נעשה שימוש בשפה המקומית ובכתב המקומי של המיקום כברירת מחדל. |
region |
regionCode |
השם שונה. אם משמיטים את הפרמטר, ערך ברירת המחדל בגרסה 3 הוא us, ואילו בגרסה 4 אין ערך ברירת מחדל. |
extra_computations |
הוסר | הוחלפה ב-SearchDestinations. |
שינויים בשדה התשובה
| שדה בגרסה 3 | שדה בגרסה 4 | הערות |
|---|---|---|
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 >1). |
results.partial_match |
הוסר | |
| חדש | results.addressComponents.languageCode |
השפה של רכיב הכתובת הספציפי. |
| חדש | results.bounds |
גבולות מפורשים באמצעות high/low. |
| חדש | results.place |
שם המשאב של המקום. |
| חדש | results.postalAddress |
אובייקט PostalAddress מובנה. |
שחזור מסנני רכיבים בגרסה 3
המרת כתובות לקואורדינטות (geocoding) בגרסה 3 של Geocoding כללה פרמטר components שאפשר סינון קשיח של תוצאות לרכיבים ספציפיים (למשל, components=country:US). המרת כתובות לקואורדינטות בגרסה 4 לא תומכת בסוג הזה של סינון קשיח בפרמטרים של הבקשה. בגרסה 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:
| מסנן רכיבים בגרסה 3 | שדה תשובה בגרסה 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 בבקשה כולל קיצור סטנדרטי של 2 אותיות. יכול להיות שהערך של postalAddress.administrativeArea בתגובה לא יתאים ישירות לסיומות של קודי ISO 3166-2, מכמה סיבות. קודם כול, באזורים מסוימים, חלוקת המשנה שתואמת לקוד ISO 3166-2 היא לא חלק מהייצוג הסטנדרטי של כתובות דואר. לדוגמה, בספרד, האזור המנהלי ברמה 1 (למשל, "CN" עבור Canarias) עשוי להופיע ב-addressComponents, אבל postalAddress.administrativeArea עשוי להכיל את האזור ברמה 2 (למשל, "Santa Cruz de Tenerife"). שנית, באזורים מסוימים לא נהוג להשתמש בקיצור של החלוקה המנהלית, והיא מיוצגת ב-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" במיקוד בארה"ב). לוגיקת הנורמליזציה הספציפית הנדרשת תשתנה בהתאם למדינה ולפורמטים של המיקודים הרלוונטיים. יכול להיות שתצטרכו להתאים את פונקציות הנורמליזציה שסופקו או להטמיע לוגיקה מתוחכמת יותר לאזורים שאתם מטרגטים.
הדוגמה שמוצגת כאן מתייחסת למיקודים בארה"ב ומאפשרת התאמה ל-5 הספרות הראשונות, גם אם המיקוד שסופק או הוחזר כולל 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');
מעבר מ-v3 Reverse Geocoding
אם אתם משתמשים ב-v3 Reverse Geocoding כדי להמיר קואורדינטות לכתובות, אתם צריכים לעבור ל-v4 Reverse geocode a location, שמקבלת בקשת GET.
בגרסה 4 של ה-API יש שינויים בשמות, במבנה ובתמיכה בכמה פרמטרים. מומלץ מאוד להשתמש במסכת שדה כדי לציין את השדות שרוצים להחזיר בתגובה.
בקשה לשינוי פרמטרים
| פרמטר בגרסה 3 | פרמטר v4 | הערות |
|---|---|---|
language |
languageCode |
השם שונה. אם משמיטים את הפרמטר, בגרסה 3 נעשה שימוש בכותרת Accept-Language או בערך ברירת המחדל en, ואילו בגרסה 4 נעשה שימוש בשפה המקומית ובכתב המקומי של המיקום כברירת מחדל. |
region |
regionCode |
השם שונה. אם משמיטים את הפרמטר, ערך ברירת המחדל בגרסה 3 הוא us, ואילו בגרסה 4 אין ערך ברירת מחדל. |
result_type |
types |
שונה השם; משתמש בפרמטרים חוזרים של שאילתות. |
location_type |
granularity |
שונה השם; משתמש בפרמטרים חוזרים של שאילתות. |
extra_computations |
הוסר | הוחלפה ב-SearchDestinations. |
שינויים בשדה התשובה
| שדה בגרסה 3 | שדה בגרסה 4 | הערות |
|---|---|---|
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 v3, העברת extra_computations=ADDRESS_DESCRIPTORS החזירה אובייקט address_descriptor שמכיל את landmarks[] ו-areas[]. בגרסה 4 של Geocoding API, היכולת הזו מוחלפת בשיטה SearchDestinations (POST /v4/geocode/destinations), שמחזירה הקשר מרחבי עשיר ישירות בתוך כל אובייקט Destination.
בטבלה הבאה מפורטים השדות בגרסה הקודמת (v3) של address_descriptor והשדות המקבילים בגרסה החדשה (v4) של SearchDestinations:
שדה address_descriptor בגרסה 3 |
שדה v4 SearchDestinations |
הערות לגבי ההעברה |
|---|---|---|
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 |
במקום ערך enum גולמי (ACROSS_THE_ROAD, AROUND_THE_CORNER), גרסה 4 מחזירה ביטוי מקומי שקריא לאנשים (למשל, "Across from Central Park"). |
landmarks[].straight_line_distance_meters |
landmarks[].straightLineDistanceMeters |
השם שונה ל-camelCase קטן. |
landmarks[].travel_distance_meters |
landmarks[].travelDistanceMeters |
השם שונה ל-camelCase קטן. |
areas[] (containment enum) |
destinations[].containingPlaces[] וגם subDestinations[] |
השווה ערך הקרוב ביותר הזמין להיררכיה מבנית: מתחמים, קמפוסים, קניונים ובניינים מקיפים מוחזרים כאובייקטים מובנים של PlaceView ב-containingPlaces[] וב-subDestinations[] (כאשר structureType מוגדר ל-GROUNDS או ל-BUILDING וקווי מתאר אופציונליים של displayPolygon). שימו לב שאין תחליף ישיר של 1:1 לאזורי קרבה של שכונה/מחוז או לערך הטיפוס המוגדר (enum) של גרסה 3 (containment) (NEAR, WITHIN, OUTSKIRTS). |
מעבר מהמרת כתובות לקואורדינטות של מקומות בגרסה 3
אם אתם משתמשים ב-place_id כדי לקבל את הכתובת של מזהה מקום ספציפי באמצעות Geocoding v3, אתם צריכים לעבור לשיטה Place Geocoding בגרסה v4, שמקבלת בקשת GET.
בגרסה 4 של ה-API יש שינויים בשמות, במבנה ובתמיכה בכמה פרמטרים. מומלץ מאוד להשתמש במסכת שדה כדי לציין את השדות שרוצים להחזיר בתגובה.
בקשה לשינוי פרמטרים
| פרמטר בגרסה 3 | פרמטר v4 | הערות |
|---|---|---|
place_id |
השדה place בבקשת הפרוטוקול |
מזהה המקום מסופק עכשיו כפרמטר של הנתיב places/{place}, לדוגמה: https://geocode.googleapis.com/v4/geocode/places/ChIJj61dQgK6j4AR4GeTYWZsKWw. השדה הזה ממופה לשדה המקום בבקשה הבסיסית. |
language |
languageCode |
השם שונה. אם משמיטים את הפרמטר, בגרסה 3 נעשה שימוש בכותרת Accept-Language או בערך ברירת המחדל en, ואילו בגרסה 4 נעשה שימוש בשפה המקומית ובכתב המקומי של המיקום כברירת מחדל. |
region |
regionCode |
השם שונה. אם משמיטים את הפרמטר, ערך ברירת המחדל בגרסה 3 הוא us, ואילו בגרסה 4 אין ערך ברירת מחדל. |
שינויים בשדה התשובה
| שדה בגרסה 3 | שדה בגרסה 4 | הערות |
|---|---|---|
status, error_message |
הוסר | בגרסה 4 נעשה שימוש בקודי סטטוס של HTTP ובגופי שגיאות. |
results |
(root) | גרסה 4 מחזירה אובייקט תוצאה יחיד, ולא מערך 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 >1). |
| חדש | addressComponents.languageCode |
השפה של רכיב הכתובת הספציפי. |
| חדש | bounds |
גבולות מפורשים באמצעות high/low. |
| חדש | place |
שם המשאב של המקום. |
| חדש | postalAddress |
אובייקט PostalAddress מובנה. |
מעבר מהמרת כתובות לקואורדינטות (geocoding) של נתונים לקהילה ממוקדת אל Destinations
התכונות הבאות ב-Geocoding API v3 מוחלפות ב-method SearchDestinations של Geocoding API v4:
- כניסות
- נקודות ניווט
- קווי מתאר של מבנים
- שטחים
אם השתמשתם ב-Geocoding API v3 בשביל התכונות שלמעלה, אתם יכולים להיעזר במסמך הזה כדי להשתמש ב-method SearchDestinations במקום זאת כדי לקבל את התכונות האלה.
במסמך הזה מוסבר איפה בתגובה של SearchDestinations אפשר למצוא את המאפיינים האלה, ומה ההבדלים בייצוג של המאפיינים האלה בתגובות של ה-API בין Geocoding API v3 לבין השיטה SearchDestinations של Geocoding API v4.
כניסות
כדי לקבל את הכניסות שמשויכות ל-destination, משתמשים בשדה destination.entrances.
לכל entrance ב-destination.entrances יש את השדות הבאים (שמחליפים את הסכימה הקודמת של גרסה 3, buildings.entrances):
-
displayName– שדה אופציונלי חדש שמכיל שם קריא לאנשים של הכניסה, לדוגמה"Gate B". -
location– מיקום מסוגLatLngבאמצעותlatitudeו-longitude(מחליף אתlat/lngבגרסה 3). -
tags– זהה לשדהtagsמכניסות של Geocoding API v3 (כמוPREFERRED). -
place– שם המשאב של המקום (לדוגמה,places/ChIJ...), שמחליף את השדהbuilding_place_idמ-Geocoding API v3. בגרסה 4, המקום הזה יכול לייצג כל מבנה של יעד (בניין, קמפוס או פארק), ולא רק בניין.
נקודות ניווט
כדי לקבל את נקודות הניווט שמשויכות ל-destination, משתמשים בשדה destination.navigationPoints.
לכל navigationPoint ב-destination.navigationPoints יש את השדות הבאים (שמחליפים את הסכימה הקודמת של גרסה 3, navigation_points):
-
navigationPointToken– מחרוזת טוקן מוצפנת שמשמשת לניתוב לנקודת הניווט הספציפית הזו ב-methodComputeRoutes(Waypoint.navigationPointToken) של Routes API. מידע נוסף זמין במאמר ניתוב באמצעות טוקנים של נקודות ניווט. -
displayName– שדה אופציונלי חדש שמכיל שם קריא לאנשים של נקודת הניווט, לדוגמה"5th Ave". -
location– מיקום מסוגLatLngבאמצעותlatitudeו-longitude. -
travelModes– דומה לשדהrestricted_travel_modesב-Geocoding API v3, אבל בגרסה 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 של גרסה 3 הקודמת). לכל placeView, בודקים אם מדובר בפוליגון של שטח באמצעות השדה placeView.structureType. אם סוג המבנה הוא GROUNDS, אפשר לקבל את המתאר מהשדה placeView.displayPolygon. ב-placeView יהיו גם שדות נוספים לשטחים שלא היו ב-Geocoding API v3.
אובייקט destination יכול להכיל אובייקט placeView שמייצג שטח בשדות הבאים:
destination.primarydestination.containingPlacesdestination.subDestinations
שימו לב שהפורמט של placeView.displayPolygon תואם לפורמט של מתאר השטח ב-Geocoding API v3, שהוא פורמט GeoJSON, באמצעות פורמט RFC 7946.
רמת הדיוק של התוצאות
בגרסה 3 של Geocoding API, השדה location_type בגיאומטריית התגובה ציין את רמת הדיוק של התוצאות, וחלק מהלקוחות דירגו או סיננו את התוצאות על סמך הערכים האלה (ROOFTOP, RANGE_INTERPOLATED, GEOMETRIC_CENTER ו-APPROXIMATE). בהעברות רגילות לגרסה 4 של Geocoding API, השם של השדה הזה משתנה ל-granularity.
ב-Destinations API (גרסה 4 SearchDestinations), אין שדה location_type. במקום זאת, המידע המרחבי מטופל באופן שונה:
- אין צורך בסינון ידני בצד הלקוח: בעוד שהמרת כתובות רגילה לקואורדינטות מספקת כמה תוצאות ברמות פירוט שונות, השיטה
SearchDestinationsמצמצמת את חוסר הבהירות על ידי פתרון ליעד אחד שעבר אופטימיזציה בכל פעם שאפשר. כך הלקוחות לא צריכים לסנן לפי סוג המיקום כדי לקבוע איזו תוצאה היא הטובה ביותר. - מידע מרחבי שמיוצג על ידי סוג המבנה ומצולעי התצוגה:
הגיאומטריה והמבנה המרחביים מצוינים על ידי:
displayPolygon(לגיאומטריה מדויקת).- השדה
structureTypeבתוך האובייקטplaceView.
- מיפוי סוג המבנה:
-
structureTypeשלPOINT, BUILDINGאוSECTIONבדרך כלל תואם למה שנקרא בעברROOFTOP. - ערך
structureTypeשלGROUNDSבדרך כלל תואם לערך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, אפשר להשתמש במתכוני הקוד הבאים כדי לחלץ מבנים נפוצים של מרחב וכתובות.
חילוץ הפוליגון הטוב ביותר של המבנה
אם רוצים להציג את שטח המבנה של מיקום או יעד:
- בודקים אם המקום
primaryכוללstructureType === '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) בגרסה 3 address_descriptor החזירה טיפוס מוגדר מראש (enum) של spatial_relationship (WITHIN, BESIDE, BEHIND, NEAR, ACROSS_THE_ROAD, AROUND_THE_CORNER). ב-SearchDestinations:
- אין ערך enum גולמי של קשר. במקום זאת, צריך להשתמש ישירות ב-
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שלו ל-methodComputeRoutesשל Routes 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 v4 הוא ממשק API לתקשורת שרת-אל-שרת. אין דרך ישירה להעביר משתמשי JavaScript מגרסה 3 לגרסה 4. אם תפעילו את השיטות של גרסה 4 ישירות מ-JavaScript בצד הלקוח (לדוגמה, בדפדפן) באמצעות מפתח API, מפתח ה-API שלכם יהיה חשוף לסיכון גבוה של גניבה ושימוש לרעה.
הגבלות על הגורמים המפנים מסוג HTTP, למרות שהן שימושיות, לא מספקות הגנה מספיקה לנקודות קצה של שירותי אינטרנט, כי תוקפים יכולים לעקוף אותן בקלות על ידי זיוף הכותרת Referer בבקשות שלהם.
גישה מומלצת
הדרך המומלצת להשתמש ב-Geocoding API v4 היא משרת בק-אנד משלכם. אפליקציית הלקוח צריכה לשלוח בקשות לשרת המתווך הזה, ואז הוא קורא ל-Google API באופן מאובטח באמצעות מפתח API מוגן (לדוגמה, מפתח שמאוחסן במשתנה סביבה או במנהל סודות). כך מפתח ה-API לא ייחשף אף פעם בקוד של ממשק המשתמש.
חלופות לצרכים בצד הלקוח
אם אתם צריכים לבצע המרת כתובות לקואורדינטות בצד הלקוח, אתם יכולים להשתמש באחד מהפתרונות הקיימים בצד הלקוח:
- שירות המרת כתובות לקואורדינטות (geocoding) ב-Maps JavaScript API: שירות המרת הכתובות לקואורדינטות ממשיך להשתמש בקצה העורפי של גרסה 3, והוא מיועד לשימוש בסביבת דפדפן.
- Places UI Kit: משתמשים ב-Places UI Kit, כולל רכיבי השלמה אוטומטית למקומות, בשביל רכיבים של ממשק המשתמש שקשורים לכתובות.