نقل البيانات من الإصدار 3 إلى الإصدار 4 من Geocoding API

المطوّرون في المنطقة الاقتصادية الأوروبية

يقدّم الإصدار 4 من Geocoding API عدة طرق جديدة تحلّ محلّ الوظائف في الإصدار 3 من واجهة برمجة التطبيقات. يوضّح لك هذا الدليل كيفية نقل تطبيقك لاستخدام طرق الإصدار 4 الجديدة.

يمكنك استخدام مفاتيح واجهة برمجة التطبيقات الحالية مع طرق الإصدار 4 الجديدة. ومع ذلك، إذا طلبت زيادة الحصة في الإصدار 3 من واجهة برمجة التطبيقات، يجب طلب زيادة في الإصدار 4 الجديد من واجهات برمجة التطبيقات.

نقل البيانات من الإصدار 3 من الترميز الجغرافي المباشر

إذا كنت تستخدم الإصدار الثالث من الترميز الجغرافي لترميز العناوين جغرافيًا، عليك الانتقال إلى طريقة الترميز الجغرافي لعنوان في الإصدار الرابع، والتي تقبل طلب استرداد بيانات باستخدام GET.

يغيّر الإصدار 4 من واجهة برمجة التطبيقات الأسماء والبنية والدعم لعدة مَعلمات. ننصحك بشدة باستخدام قناع حقل لتحديد الحقول التي تريد عرضها في الاستجابة.

طلب تغييرات على المَعلمات

مَعلمة v3 مَعلمة 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 حقل 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 قيمة أكبر من 1).
results.partial_match مُزال
الأرباح الجديدة results.addressComponents.languageCode لغة مكوّن العنوان المحدّد
الأرباح الجديدة results.bounds حدود صريحة باستخدام high/low
الأرباح الجديدة results.place اسم المورد للمكان
الأرباح الجديدة results.postalAddress عنصر PostalAddress منظَّم

إعادة إنتاج فلاتر مكوّنات الإصدار 3

تضمّنت ميزة "الترميز الجغرافي المباشر" في الإصدار الثالث من Geocoding مَعلمة components التي أتاحت الفلترة الصارمة للنتائج لمكوّنات معيّنة (مثل components=country:US). لا تتيح ميزة "الترميز الجغرافي المباشر" في الإصدار الرابع هذا النوع من الفلترة الصارمة في مَعلمات الطلب. في الإصدار 4، يمكنك تقديم معلومات العنوان إما كسلسلة واحدة غير منظَّمة في المسار أو كمَعلمات طلب بحث منظَّمة، مثل address.addressLines وaddress.locality وaddress.administrativeArea وaddress.postalCode وaddress.regionCode. لا تعمل المَعلمات المنظَّمة كفلاتر صارمة. بدلاً من ذلك، يتم دمج جميع المكوّنات المقدَّمة لتشكيل العنوان الكامل الذي ستحاول واجهة برمجة التطبيقات ترميزه جغرافيًا. تبحث واجهة برمجة التطبيقات عن أفضل مطابقة للعنوان الكامل المحدّد في جميع المكوّنات. يمكن أن يساعد تقديم المكوّنات بطريقة منظَّمة واجهة برمجة التطبيقات في فهم الغرض بشكل أفضل، خاصةً عندما يتم جمع معلومات العنوان من حقول نماذج منفصلة. يمكن أن يساعد ذلك واجهة برمجة التطبيقات في معالجة الأخطاء الإملائية البسيطة أو حالات الالتباس داخل كل مكوّن، لأنّ نوع المعلومات في كل حقل يكون واضحًا.

للحصول على سلوك مشابه لفلاتر المكوّنات الصارمة في الإصدار 3، عليك تنفيذ الفلترة من جهة العميل على مصفوفة results التي يعرضها الإصدار 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 في كل نتيجة. يُرجى العِلم أنّه على الرغم من أنّ واجهة برمجة التطبيقات تقبل رموز المناطق المكتوبة بأحرف صغيرة في الطلب، فإنّها تعرضها دائمًا بأحرف كبيرة في الردّ، لذا يجب توحيد الإدخال إلى أحرف كبيرة قبل المقارنة.

مثال على رمز 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 جزءًا من التمثيل العادي للعناوين البريدية. على سبيل المثال، في إسبانيا، قد يظهر المستوى 1 من المنطقة الإدارية (مثل "CN" لجزر الكناري) في addressComponents، ولكن قد يحتوي postalAddress.administrativeArea على المستوى 2 من المنطقة (مثل "سانتا كروز دي تينيريف"). ثانيًا، في بعض المناطق، لا يتم استخدام اختصار التقسيم الفرعي بشكل شائع ويتم تمثيله في 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 أرقام حتى إذا تم تقديم أو عرض الرمز البريدي المكوّن من 9 أرقام.

مثال على رمز 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 من واجهة برمجة التطبيقات Reverse Geocoding API

إذا كنت تستخدم الإصدار الثالث من عكس الترميز الجغرافي لتحويل الإحداثيات إلى عناوين، عليك نقل بياناتك إلى الإصدار الرابع من طريقة عكس الترميز الجغرافي لموقع جغرافي التي تقبل طلب استرداد بيانات باستخدام GET.

يغيّر الإصدار 4 من واجهة برمجة التطبيقات الأسماء والبنية والدعم لعدة مَعلمات. ننصحك بشدة باستخدام قناع حقل لتحديد الحقول التي تريد عرضها في الاستجابة.

طلب تغييرات على المَعلمات

مَعلمة v3 مَعلمة v4 ملاحظات
language languageCode تمت إعادة التسمية. في حال حذف هذه المَعلمة، يستخدم الإصدار الثالث العنوان Accept-Language أو الإعداد التلقائي en، في حين يستخدم الإصدار الرابع الإعداد التلقائي للغة المحلية والنص البرمجي للموقع الجغرافي.
region regionCode تمت إعادة التسمية. عند حذفها، يتم ضبط الإصدار 3 تلقائيًا على us، في حين لا يتضمّن الإصدار 4 قيمة تلقائية.
result_type types تمت إعادة تسميتها، وتستخدم معلمات طلب بحث متكررة.
location_type granularity تمت إعادة تسميتها، وتستخدم معلمات طلب البحث المتكررة.
extra_computations مُزال تم استبدالها بطريقة SearchDestinations.

تغييرات حقل الردّ

حقل الإصدار 3 حقل 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

في الإصدار 3 من Geocoding API، كان تمرير extra_computations=ADDRESS_DESCRIPTORS يعرض عنصر address_descriptor يحتوي على landmarks[] وareas[]. في الإصدار 4 من Geocoding API، تم استبدال هذه الميزة بالطريقة SearchDestinations (POST /v4/geocode/destinations)، التي تعرض سياقًا مكانيًا غنيًا مباشرةً داخل كل عنصر Destination.

يعرض الجدول التالي حقول address_descriptor القديمة في الإصدار 3 ومثيلاتها في الإصدار 4 من SearchDestinations:

حقل v3 address_descriptor حقل 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 بدلاً من تعداد أولي (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 اختيارية). يُرجى العِلم أنّه لا يوجد بديل مباشر بنسبة 1:1 لمناطق التقارب في الحي/المنطقة أو تعداد الإصدار 3 من containment (NEAR وWITHIN وOUTSKIRTS).

نقل البيانات من الإصدار 3 من الترميز الجغرافي للأماكن

إذا كنت تستخدم place_id للحصول على عنوان لرقم تعريف مكان معيّن باستخدام الإصدار 3 من Geocoding، عليك الانتقال إلى طريقة الترميز الجغرافي للمكان في الإصدار 4 التي تقبل طلب استرداد بيانات باستخدام GET.

يغيّر الإصدار 4 من واجهة برمجة التطبيقات الأسماء والبنية والدعم لعدة مَعلمات. ننصحك بشدة باستخدام قناع حقل لتحديد الحقول التي تريد عرضها في الاستجابة.

طلب تغييرات على المَعلمات

مَعلمة v3 مَعلمة 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 حقل v4 ملاحظات
‫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 Hyperlocal Data إلى Destinations

سيتم استبدال الميزات التالية في الإصدار 3 من Geocoding API بطريقة SearchDestinations في الإصدار 4 من Geocoding API:

  • مرّات الدخول
  • نقاط التنقّل
  • مخططات المباني
  • الأراضي المحيطة

إذا كنت تستخدم الإصدار 3 من Geocoding API للميزات المذكورة أعلاه، يمكنك استخدام هذا المستند لمساعدتك في استخدام طريقة SearchDestinations بدلاً من ذلك للحصول على هذه الميزات. يوضّح هذا المستند مكان العثور على هذه الميزات في ردّ SearchDestinations، والاختلافات في كيفية تمثيل هذه الميزات في ردود واجهة برمجة التطبيقات بين الإصدار 3 من Geocoding API وطريقة SearchDestinations في الإصدار 4 من Geocoding API.

مرّات الدخول

للحصول على المداخل المرتبطة بـ destination، استخدِم الحقل destination.entrances.

يحتوي كل entrance في destination.entrances على الحقول التالية (لتحلّ محلّ المخطّط القديم buildings.entrances من الإصدار 3):

  • ‫displayName: حقل اختياري جديد يحتوي على اسم للمدخل يمكن لشخص عادي قراءته، مثل "Gate B"
  • ‫location: موقع جغرافي من النوع LatLng باستخدام latitude وlongitude (يحلّ محلّ الإصدار 3 من lat/lng).
  • ‫tags: هو نفسه حقل tags من مداخل الإصدار 3 من Geocoding API (مثل PREFERRED).
  • ‫place: اسم المورد الخاص بالمكان (مثلاً، places/ChIJ...)، ويحلّ محلّ الحقل building_place_id من الإصدار 3 من Geocoding API في الإصدار 4، يمكن أن يمثّل هذا المكان أي بنية وجهة (مبنى أو مجمّع أو متنزّه)، وليس مبنى فقط.

للحصول على نقاط التنقّل المرتبطة بـ destination، استخدِم الحقل destination.navigationPoints.

يحتوي كل navigationPoint في destination.navigationPoints على الحقول التالية (لتحلّ محلّ المخطّط القديم navigation_points من الإصدار 3):

  • ‫navigationPointToken: سلسلة رموز مميّزة مشفّرة تُستخدَم للتوجيه إلى نقطة التنقّل المحدّدة هذه في طريقة ComputeRoutes في Routes API (Waypoint.navigationPointToken). يُرجى الاطّلاع على المسار باستخدام الرموز المميّزة لنقاط التنقّل.
  • ‫displayName: حقل اختياري جديد يحتوي على اسم يمكن لشخص عادي قراءته لنقطة التنقّل، مثل "5th Ave"
  • ‫location: موقع جغرافي من النوع LatLng باستخدام latitude وlongitude
  • ‫travelModes: يشبه حقل restricted_travel_modes من الإصدار 3 من Geocoding API، باستثناء أنّ الإصدار 4 يحدّد أوضاع السفر المقبولة (DRIVE وWALK) بدلاً من أوضاع السفر المحظورة.
  • ‫usage: حقل جديد يحدّد حالات استخدام الوصول المتوافقة لنقطة التنقّل (مثل PICKUP أو DROPOFF أو PARKING).

مخططات المباني

للحصول على مخطّطات المباني المرتبطة بـ destination، استخدِم حقل displayPolygon في عناصر placeView في destination التي تمثّل المباني (استبدال مصفوفة buildings.building_outlines القديمة في الإصدار 3). بالنسبة إلى كل placeView، تحقَّق مما إذا كان مبنى يحتوي على الحقل placeView.structureType. إذا كان نوع البنية هو BUILDING، يمكنك الحصول على المخطط من الحقل placeView.displayPolygon. ستتضمّن placeView أيضًا حقولاً إضافية للمبنى لم تكن متوفّرة في الإصدار 3 من Geocoding API.

يمكن أن يحتوي destination على عنصر placeView يمثّل مبنى في الحقول التالية:

  • ‫destination.primary: المكان الأساسي للوجهة
  • ‫destination.containingPlaces: حقل متكرّر يتضمّن الأماكن الأكبر التي "تحتوي" على المكان الأساسي على سبيل المثال، إذا كان المكان الأساسي هو subpremise، يحتوي containingPlaces عادةً على placeView الذي يمثّل المبنى.
  • ‫destination.subDestinations: حقل متكرّر يحتوي على وجهات فرعية للمكان الأساسي (على سبيل المثال، وحدات سكنية أو أجنحة فردية داخل مبنى)

يُرجى العِلم أنّ تنسيق placeView.displayPolygon يتطابق مع تنسيق مخطط المبنى في الإصدار 3 من Geocoding API، وهو تنسيق GeoJSON، باستخدام تنسيق RFC 7946.

الأراضي المحيطة

على غرار مخططات المباني، للحصول على الأراضي المرتبطة بـ destination، استخدِم حقل displayPolygon لكائنات placeView في destination التي تمثّل الأراضي (استبدال مصفوفة grounds القديمة في الإصدار 3). بالنسبة إلى كل placeView، تحقَّق مما إذا كان مضلّعًا للأراضي باستخدام الحقل placeView.structureType. إذا كان نوع البنية هو GROUNDS، يمكنك الحصول على المخطط من الحقل placeView.displayPolygon. ستتضمّن placeView أيضًا حقولاً إضافية للأراضي التي لم تكن متوفّرة في الإصدار 3 من Geocoding API.

يمكن أن يتضمّن عنصر destination عنصر placeView يمثّل أرضًا في الحقول التالية:

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

يُرجى العِلم أنّ تنسيق placeView.displayPolygon يتطابق مع تنسيق مخطط الأراضي في الإصدار 3 من Geocoding API، وهو تنسيق 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 قناع حقل، كما هو موضّح في مقالة اختيار الحقول المطلوب عرضها. يمكن ضبط قناع الحقل على * لعرض جميع الحقول، أو يمكنك ضبطه على الحقول المحدّدة التي تريد تلقّيها. على سبيل المثال، يضبط طلب البيانات التالي من واجهة برمجة التطبيقات قناع الحقل لتلقّي جميع الحقول المطلوبة للحصول على المداخل ونقاط التنقّل والمخططات التفصيلية للمباني وأراضي الوجهة:

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

وصفات نقل البيانات الشائعة وأنماط الرموز البرمجية

عند نقل عمليات سير العمل المعقّدة من Geocoding v3 أو Geocoding++‎ إلى SearchDestinations، استخدِم وصفات الرموز البرمجية التالية لاستخراج البُنى المكانية وبُنى العناوين الشائعة.

استخراج أفضل مضلّع للمبنى

إذا أردت عرض مساحة المبنى لموقع جغرافي أو وجهة:

  1. تحقَّق مما إذا كان المكان primary يحتوي على structureType === 'BUILDING' ويتضمّن displayPolygon.
  2. إذا لم يكن الأمر كذلك، افحص containingPlaces للعثور على المبنى المحيط (مفيد عندما تكون الوجهة الأساسية وجهة فرعية لمبنى أكبر).
  3. إذا لم يتم العثور على مبنى محيط، يُرجى التحقّق من subDestinations لمعرفة ما إذا كانت المباني الفردية مدرَجة.
مثال على رمز Python
def get_best_building_polygon(destination):
    primary = destination.get('primary', {})
    if primary.get('structureType') == 'BUILDING' and 'displayPolygon' in primary:
        return primary['displayPolygon']

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

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

    return None
مثال على رمز Node.js
function getBestBuildingPolygon(destination) {
    const { primary = {}, containingPlaces = [], subDestinations = [] } = destination;

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

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

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

استخراج مخطط الملعب

إذا كنت بحاجة إلى حدود مجمّع سكني أو مجمّع شركات أو مركز تسوّق أو متنزّه:

  1. إذا كان المكان primary يمثّل المجمّع بأكمله (structureType === 'GROUNDS')، استخدِم primary.displayPolygon.
  2. إذا كان المكان "primary" عبارة عن مبنى أو مدخل يقع داخل مجمّع أكبر، ابحث عن الأراضي المحيطة به في "containingPlaces".
مثال على رمز Python
def get_grounds_polygon(destination):
    primary = destination.get('primary', {})
    if primary.get('structureType') == 'GROUNDS' and 'displayPolygon' in primary:
        return primary['displayPolygon']

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

    return None
مثال على رمز Node.js
function getGroundsPolygon(destination) {
    const { primary = {}, containingPlaces = [] } = destination;

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

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

اختيار معالم لعرض العنوان مقابل الوصول إلى الوجهة النهائية

أرجع الإصدار الثالث من Geocoding 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 إلى طريقة ComputeRoutes (Waypoint.navigationPointToken) في Routes API أو 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,
    };
}

الاعتبارات الأمنية

تم تصميم الإصدار 4 من Geocoding API كواجهة برمجة تطبيقات بين الخوادم. لا يتوفّر مسار نقل مباشر لمستخدمي JavaScript من الإصدار 3 إلى الإصدار 4. إنّ استدعاء طرق الإصدار 4 مباشرةً من JavaScript من جهة العميل (على سبيل المثال، في متصفّح) باستخدام مفتاح واجهة برمجة التطبيقات يعرّض مفتاح واجهة برمجة التطبيقات لخطر كبير يتمثّل في السرقة وإساءة الاستخدام.

على الرغم من أنّ القيود المفروضة على مُحيل HTTP مفيدة، إلا أنّها لا توفّر حماية كافية لنقاط نهاية خدمة الويب، إذ يمكن للمهاجمين تجاوزها بسهولة من خلال تزوير عنوان Referer في طلباتهم.

الطريقة المقترَحة لاستخدام الإصدار 4 من Geocoding API هي من خلال خادم الخلفية الخاص بك. يجب أن يرسل تطبيق العميل الطلبات إلى هذا الخادم الوسيط، الذي يستدعي بعد ذلك Google API بأمان باستخدام مفتاح واجهة برمجة تطبيقات محمي (على سبيل المثال، مفتاح مخزَّن في متغيّر بيئة أو مدير أسرار). يضمن ذلك عدم الكشف عن مفتاح واجهة برمجة التطبيقات في الرمز البرمجي للواجهة الأمامية.

بدائل لاحتياجات من جهة العميل

إذا كانت لديك احتياجات من جهة العميل تتطلّب الترميز الجغرافي، ننصحك باستخدام أحد الحلول الحالية من جهة العميل: