جستجوی نوشتار (جدید)

پلاتفرم را انتخاب کنید: Android iOS JavaScript سرویس وب
توسعه‌دهندگان منطقه اقتصادی اروپا (EEA)

«جستجوی نوشتار (جدید)» پُرسمان نوشتاری را می‌گیرد و فهرستی از مکان‌های منطبق را برمی‌گرداند.

«جستجوی نوشتار (جدید)» اطلاعاتی درباره مجموعه‌ای از مکان‌ها براساس یک رشته برمی‌گرداند — برای مثال «پیتزا در نیویورک» یا «کفش‌فروشی‌های نزدیک اتاوا» یا «خیابان اصلی ۱۲۳». سرویس با فهرستی از مکان‌های منطبق با رشته نوشتاری و هرگونه سوگیری مکانی که تنظیم شده است پاسخ می‌دهد. «جستجوی نوشتار (جدید)» به شما امکان می‌دهد مکان‌ها را براساس نوع جستجو کنید، بااستفاده از معیارهایی مثل ساعت کاری و رده‌بندی فیلتر کنید، و نتایج را به مکان خاصی محدود یا متمایل کنید.

برای استفاده از «جستجوی نوشتار (جدید)»، باید «Places API (جدید)» را در پروژه Google Cloud خود فعال کنید. برای جزئیات، به شروع به کار مراجعه کنید.

یافتن مکان با پُرسمان نوشتاری

برای برگرداندن فهرستی از مکان‌ها از پُرسمان نوشتاری یا شماره تلفن، با searchByText تماس بگیرید. پارامترهای جستجو را بااستفاده از درخواست مشخص کنید و سپس searchByText() را فراخوانی کنید. نتایج به‌صورت فهرستی از اشیاء Place برگردانده می‌شود که از آن می‌توانید جزئیات مکان را دریافت کنید. گزیده زیر نمونه‌ای از درخواست و تماس با searchByText را نشان می‌دهد:

TypeScript

const request = {
    textQuery: query,
    fields: ['displayName', 'location', 'businessStatus'],
    includedType: '', // Restrict query to a specific type (leave blank for any).
    useStrictTypeFiltering: true,
    locationRestriction: map.getBounds(),
    isOpenNow: true,
    language: 'en-US',
    maxResultCount: 8,
    minRating: 1, // Specify a minimum rating.
    region: 'us',
};

const { places } = await Place.searchByText(request);

JavaScript

const request = {
    textQuery: query,
    fields: ['displayName', 'location', 'businessStatus'],
    includedType: '', // Restrict query to a specific type (leave blank for any).
    useStrictTypeFiltering: true,
    locationRestriction: map.getBounds(),
    isOpenNow: true,
    language: 'en-US',
    maxResultCount: 8,
    minRating: 1, // Specify a minimum rating.
    region: 'us',
};

const { places } = await Place.searchByText(request);
  • با پارامتر textQuery، پُرسمان نوشتاری یا شماره تلفنی را برای جستجو مشخص کنید.
  • از پارامتر fields (الزامی) برای مشخص کردن فهرست جداشده با کاما از یک یا چند فیلد داده در نگارش شتری استفاده کنید. فیلدهایی که درخواست می‌کنید قیمت درخواست را تعیین می‌کند. انتخاب فیلدهای داده را ببینید.
  • از پارامتر includedType برای برگرداندن نتایج نوع مشخص‌شده استفاده کنید.
  • از locationBias یا locationRestriction برای سوگیری یا محدود کردن نتایج جستجوی نوشتاری به منطقه‌ای خاص استفاده کنید.
فهرست کامل محل‌های اقامت را ببینید.

اگر پُرسمان حاوی شماره تلفن است، پارامتر منطقه باید تنظیم شود. برای مثال، اگر از شماره تلفن برای جستجوی مکانی در ژاپن استفاده می‌کنید و دامنه درخواست‌کننده jp است، باید پارامتر region را روی «jp» تنظیم کنید. اگر region در درخواست حذف شود، API به‌طور پیش‌فرض به منطقه ایالات متحده (us) تنظیم می‌شود.

نتایج به‌صورت فهرستی از اشیاء Place برگردانده می‌شود که از آن می‌توانید جزئیات مکان را دریافت کنید.

مثال

مثال زیر searchByText را با نوشتار پُرسمان ارائه‌شده فراخوانی می‌کند، و سپس نقشه‌ای را با نشانگرهای قابل‌کلیک برای نمایش نتایج پُر می‌کند.

TypeScript

let map: google.maps.Map;
let markers: Record<string, google.maps.marker.AdvancedMarkerElement> = {};
let infoWindow: google.maps.InfoWindow;

async function init() {
    const [{ Map, InfoWindow }, { ControlPosition }] = await Promise.all([
        google.maps.importLibrary('maps'),
        google.maps.importLibrary('core'),
    ]);

    const center = { lat: 37.4161493, lng: -122.0812166 };
    map = new Map(document.getElementById('map')!, {
        center,
        zoom: 11,
        mapTypeControl: false,
        mapId: 'DEMO_MAP_ID',
    });

    const textInput = document.getElementById('text-input') as HTMLInputElement;
    const textInputButton = document.getElementById(
        'text-input-button'
    ) as HTMLButtonElement;
    const card = document.getElementById('text-input-card')!;
    map.controls[ControlPosition.TOP_LEFT].push(card);

    textInputButton.addEventListener('click', () => {
        void findPlaces(textInput.value);
    });

    textInput.addEventListener('keydown', (event) => {
        if (event.key === 'Enter') {
            void findPlaces(textInput.value);
        }
    });

    infoWindow = new InfoWindow();
}

async function findPlaces(query: string) {
    const [{ Place }, { AdvancedMarkerElement }] = await Promise.all([
        google.maps.importLibrary('places'),
        google.maps.importLibrary('marker'),
    ]);

    const request = {
        textQuery: query,
        fields: ['displayName', 'location', 'businessStatus'],
        includedType: '', // Restrict query to a specific type (leave blank for any).
        useStrictTypeFiltering: true,
        locationRestriction: map.getBounds(),
        isOpenNow: true,
        language: 'en-US',
        maxResultCount: 8,
        minRating: 1, // Specify a minimum rating.
        region: 'us',
    };

    const { places } = await Place.searchByText(request);

    if (places.length) {
        const { LatLngBounds } = await google.maps.importLibrary('core');
        const bounds = new LatLngBounds();

        // First remove all existing markers.
        for (const id in markers) {
            markers[id].map = null;
        }
        markers = {};

        // Loop through and get all the results.
        places.forEach((place: google.maps.places.Place) => {
            const marker = new AdvancedMarkerElement({
                map,
                position: place.location,
                title: place.displayName,
                gmpClickable: true,
            });
            markers[place.id] = marker;

            marker.addEventListener('gmp-click', () => {
                map.panTo(place.location!);
                updateInfoWindow(place.displayName!, place.id, marker);
            });

            if (place.location != null) {
                bounds.extend(place.location);
            }
        });

        map.fitBounds(bounds);
    } else {
        console.log('No results');
    }
}

// Helper function to create an info window.
function updateInfoWindow(
    title: string | Element | null,
    content: string | Element | null,
    anchor: google.maps.marker.AdvancedMarkerElement
) {
    infoWindow.setContent(content);
    infoWindow.setHeaderContent(title);
    infoWindow.open({
        map,
        anchor,
        shouldFocus: false,
    });
}

void init();

JavaScript

let map;
let markers = {};
let infoWindow;

async function init() {
    const [{ Map, InfoWindow }, { ControlPosition }] = await Promise.all([
        google.maps.importLibrary('maps'),
        google.maps.importLibrary('core'),
    ]);

    const center = { lat: 37.4161493, lng: -122.0812166 };
    map = new Map(document.getElementById('map'), {
        center,
        zoom: 11,
        mapTypeControl: false,
        mapId: 'DEMO_MAP_ID',
    });

    const textInput = document.getElementById('text-input');
    const textInputButton = document.getElementById('text-input-button');
    const card = document.getElementById('text-input-card');
    map.controls[ControlPosition.TOP_LEFT].push(card);

    textInputButton.addEventListener('click', () => {
        void findPlaces(textInput.value);
    });

    textInput.addEventListener('keydown', (event) => {
        if (event.key === 'Enter') {
            void findPlaces(textInput.value);
        }
    });

    infoWindow = new InfoWindow();
}

async function findPlaces(query) {
    const [{ Place }, { AdvancedMarkerElement }] = await Promise.all([
        google.maps.importLibrary('places'),
        google.maps.importLibrary('marker'),
    ]);

    const request = {
        textQuery: query,
        fields: ['displayName', 'location', 'businessStatus'],
        includedType: '', // Restrict query to a specific type (leave blank for any).
        useStrictTypeFiltering: true,
        locationRestriction: map.getBounds(),
        isOpenNow: true,
        language: 'en-US',
        maxResultCount: 8,
        minRating: 1, // Specify a minimum rating.
        region: 'us',
    };

    const { places } = await Place.searchByText(request);

    if (places.length) {
        const { LatLngBounds } = await google.maps.importLibrary('core');
        const bounds = new LatLngBounds();

        // First remove all existing markers.
        for (const id in markers) {
            markers[id].map = null;
        }
        markers = {};

        // Loop through and get all the results.
        places.forEach((place) => {
            const marker = new AdvancedMarkerElement({
                map,
                position: place.location,
                title: place.displayName,
                gmpClickable: true,
            });
            markers[place.id] = marker;

            marker.addEventListener('gmp-click', () => {
                map.panTo(place.location);
                updateInfoWindow(place.displayName, place.id, marker);
            });

            if (place.location != null) {
                bounds.extend(place.location);
            }
        });

        map.fitBounds(bounds);
    } else {
        console.log('No results');
    }
}

// Helper function to create an info window.
function updateInfoWindow(title, content, anchor) {
    infoWindow.setContent(content);
    infoWindow.setHeaderContent(title);
    infoWindow.open({
        map,
        anchor,
        shouldFocus: false,
    });
}

void init();

CSS

/* 
 * Always set the map height explicitly to define the size of the div element
 * that contains the map. 
 */
#map {
    height: 100%;
}

/* 
 * Optional: Makes the sample page fill the window. 
 */
html,
body {
    height: 100%;
    margin: 0;
    padding: 0;
}

#text-input-card {
    width: 25%;
    background-color: #fff;
    border-radius: 5px;
    box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
    margin: 10px;
    padding: 5px;
    font-family: Roboto, sans-serif;
    font-size: large;
    font-weight: bold;
}

#text-input {
    width: 100%;
    padding: 10px;
    margin: 0;
    box-sizing: border-box;
}

#text-input-button {
    display: inline-block;
    margin-top: 0.5rem;
    width: auto;
    padding: 0.6rem 0.75rem;
    font-size: 0.875rem;
    font-weight: 500;
    color: #fff;
    background-color: #2563eb;
    border: none;
    border-radius: 0.375rem;
    cursor: pointer;
    transition: background-color 0.15s ease-in-out;
    text-align: center;
}

HTML

<html>
    <head>
        <title>Text Search</title>

        <link rel="stylesheet" type="text/css" href="./style.css" />
        <script type="module" src="./index.js"></script>
        <script>
            // prettier-ignore
            (g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})({
                key: "GOOGLE_MAPS_API_KEY"
            });
        </script>
    </head>
    <body>
        <div id="text-input-card">
            <input
                type="text"
                id="text-input"
                placeholder="Search for a place" />
            <input type="button" id="text-input-button" value="Search" />
        </div>
        <div id="map"></div>
    </body>
</html>

انتخاب فیلدهای داده

فیلدهایی که درخواست می‌کنید قیمت هر درخواست جستجو را تعیین می‌کند. درخواست یک‌بار، با بالاترین SKU در میان فیلدهای درخواستی صورت‌حساب می‌شود. برای مثال، افزودن reviews به fields کل درخواست را به‌عنوان «جستجوی نوشتار سازمانی + Atmosphere» صورت‌حساب می‌کند.

برای نگه داشتن درخواست‌های جستجو در Text Search Pro، فقط فیلدهایی را درخواست کنید که نتایج جستجویتان نشان می‌دهد، مثل id، displayName، formattedAddress، و location.

وقتی کاربر مکانی را انتخاب می‌کند، fetchFields() را در آن مکان فراخوانی کنید تا فیلدهایی مثل reviews، nationalPhoneNumber، یا websiteURI را دریافت کنید. هر فراخوانی fetchFields() یک درخواست «جزئیات جا» جداگانه است که با بالاترین SKU در میان فیلدهایی که درخواست می‌کند صورت‌حساب می‌شود. اینکه این رویکرد باعث صرفه‌جویی در هزینه می‌شود یا نه بستگی به این دارد که کاربرانتان چند مکان را باز می‌کنند.

فیلدهایی که هر SKU را راه‌اندازی می‌کند

  • فیلدهای زیر باعث فعال شدن «واحد نگهداری موجودی» Text Search Essentials (IDs Only) می‌شوند:

    id

  • فیلدهای زیر باعث راه‌اندازی Text Search Pro SKU می‌شوند:

    accessibilityOptions
    addressComponents
    adrFormatAddress
    businessStatus
    displayName
    formattedAddress
    googleMapsUri
    iconBackgroundColor
    location
    photos
    plusCode
    svgIconMaskURI
    types
    utcOffsetMinutes
    viewport

  • فیلدهای زیر شناسه کالای سازمانی جستجوی نوشتار را راه‌اندازی می‌کنند:

    internationalPhoneNumber
    nationalPhoneNumber
    priceLevel
    rating
    regularOpeningHours
    userRatingCount
    websiteURI

  • فیلدهای زیر Text Search Enterprise + Atmosphere SKU را راه‌اندازی می‌کنند:

    allowsDogs
    editorialSummary
    evChargeOptions
    fuelOptions
    hasCurbsidePickup
    hasDelivery
    hasDineIn
    hasLiveMusic
    hasMenuForChildren
    hasOutdoorSeating
    hasRestroom
    hasTakeout
    hasWifi
    isGoodForChildren
    isGoodForGroups
    isGoodForWatchingSports
    isReservable
    parkingOptions
    paymentOptions
    reviews
    servesBeer
    servesBreakfast
    servesBrunch
    servesCocktails
    servesCoffee
    servesDessert
    servesDinner
    servesLunch
    servesVegetarianFood
    servesWine

برای SKU هر فیلد، فیلدهای داده کلاس مکان را ببینید.