התכונה "חיפוש טקסט (חדש)" מקבלת שאילתת טקסט ומחזירה רשימה של מקומות תואמים.
התכונה "חיפוש טקסט (חדש)" מחזירה מידע על קבוצה של מקומות על סמך מחרוזת – לדוגמה, "פיצה בניו יורק", "חנויות נעליים ליד אוטווה" או "רחוב הרצל 123". השירות מחזיר רשימה של מקומות שתואמים למחרוזת הטקסט ולהעדפת המיקום שהוגדרה. התכונה "חיפוש טקסט (חדש)" מאפשרת לחפש מקומות לפי סוג, לסנן לפי קריטריונים כמו שעות פעילות ודירוג, ולהגביל או להטות את התוצאות למיקום ספציפי.
כדי להשתמש בחיפוש טקסט (חדש), צריך להפעיל את 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>בחירת שדות נתונים
השדות שאתם מבקשים קובעים את המחיר של כל בקשת חיפוש. הבקשה מחויבת פעם אחת, לפי המק"ט הגבוה ביותר מבין השדות המבוקשים. לדוגמה, אם מוסיפים את השדה
reviews
ל-
fields
, כל הבקשה מחויבת לפי מק"ט חיפוש טקסט Enterprise + Atmosphere.
כדי לשמור על בקשות החיפוש ב-Text Search Pro, צריך לבקש רק את השדות שמוצגים בתוצאות החיפוש, כמו id, displayName, formattedAddress ו-location.
כשמשתמש בוחר מקום, מפעילים את fetchFields() במקום הזה כדי לקבל שדות כמו reviews, nationalPhoneNumber או websiteURI.
כל קריאה ל-fetchFields() היא בקשה נפרדת ל-Place Details, והחיוב עליה מתבצע לפי המק"ט הגבוה ביותר מבין השדות שהיא מבקשת. הגישה הזו חוסכת כסף בהתאם למספר המקומות שהמשתמשים פותחים.
השדות שמפעילים כל מק"ט
השדות הבאים מפעילים את המק"ט חיפוש טקסט Essentials (IDs Only):
idהשדות הבאים מפעילים את מק"ט חיפוש טקסט Pro:
accessibilityOptions
addressComponents
adrFormatAddress
businessStatus
displayName
formattedAddress
googleMapsUri
iconBackgroundColor
location
photos
plusCode
svgIconMaskURI
types
utcOffsetMinutes
viewportהשדות הבאים מפעילים את מק"ט Enterprise לחיפוש טקסט:
internationalPhoneNumber
nationalPhoneNumber
priceLevel
rating
regularOpeningHours
userRatingCount
websiteURIהשדות הבאים מפעילים את המק"ט "חיפוש טקסט – Enterprise + Atmosphere":
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
לגבי המק"ט של כל שדה, ראו שדות נתונים של מקומות.