地理搜尋
Meilisearch 允許您根據結果的地理位置來篩選和排序結果。當您只想取得特定區域內的結果,或是想根據與特定位置的距離來排序結果時,這會非常有用。
v0.27、v0.28 和 v0.29 中的 _geo
欄位
由於 Meilisearch 在上述版本中允許格式不正確的 _geo
欄位,請確保 _geo
欄位遵循正確的格式。
為基於位置的搜尋準備文件
為了開始根據文件的地理位置來篩選和排序文件,您必須確保它們包含有效的 _geo
欄位。
_geo
是一個保留欄位。如果您在文件中包含它,Meilisearch 會期望其值符合特定格式。
當使用 JSON 和 NDJSON 時,_geo
必須包含一個具有兩個鍵的物件:lat
和 lng
。這兩個欄位都必須包含一個浮點數或一個字串,分別表示緯度和經度。
{
…
"_geo": {
"lat": 0.0,
"lng": "0.0"
}
}
範例
假設我們有一個包含幾家餐廳的 JSON 陣列
[
{
"id": 1,
"name": "Nàpiz' Milano",
"address": "Viale Vittorio Veneto, 30, 20124, Milan, Italy",
"type": "pizza",
"rating": 9
},
{
"id": 2,
"name": "Bouillon Pigalle",
"address": "22 Bd de Clichy, 75018 Paris, France",
"type": "french",
"rating": 8
},
{
"id": 3,
"name": "Artico Gelateria Tradizionale",
"address": "Via Dogana, 1, 20123 Milan, Italy",
"type": "ice cream",
"rating": 10
}
]
一旦我們加入地理位置數據,我們的餐廳資料集看起來像這樣
[
{
"id": 1,
"name": "Nàpiz' Milano",
"address": "Viale Vittorio Veneto, 30, 20124, Milan, Italy",
"type": "pizza",
"rating": 9,
"_geo": {
"lat": 45.4777599,
"lng": 9.1967508
}
},
{
"id": 2,
"name": "Bouillon Pigalle",
"address": "22 Bd de Clichy, 75018 Paris, France",
"type": "french",
"rating": 8,
"_geo": {
"lat": 48.8826517,
"lng": 2.3352748
}
},
{
"id": 3,
"name": "Artico Gelateria Tradizionale",
"address": "Via Dogana, 1, 20123 Milan, Italy",
"type": "ice cream",
"rating": 10,
"_geo": {
"lat": 45.4632046,
"lng": 9.1719421
}
}
]
警告
嘗試索引一個或多個文件包含格式錯誤的 _geo
值的資料集,將會導致 Meilisearch 拋出一個 invalid_document_geo_field
錯誤。在這種情況下,更新將會失敗,並且不會新增或修改任何文件。
在 CSV 中使用 _geo
如果您的資料集格式為 CSV,則檔案標頭必須具有 _geo
欄。資料集中的每一列都必須包含一個以逗號分隔的字串,表示緯度和經度。
"id:number","name:string","address:string","type:string","rating:number","_geo:string"
"1","Nàpiz Milano","Viale Vittorio Veneto, 30, 20124, Milan, Italy","pizzeria",9,"45.4777599,9.1967508"
"2","Bouillon Pigalle","22 Bd de Clichy, 75018 Paris, France","french",8,"48.8826517,2.3352748"
"3","Artico Gelateria Tradizionale","Via Dogana, 1, 20123 Milan, Italy","ice cream",10,"48.8826517,2.3352748"
使用 _geoRadius
和 _geoBoundingBox
篩選結果
您可以使用 _geo
數據來篩選查詢,以便只接收位於給定地理區域內的結果。
設定
為了根據位置篩選結果,您必須將 _geo
屬性添加到 filterableAttributes
清單中
curl \
-X PUT 'https://127.0.0.1:7700/indexes/restaurants/settings/filterable-attributes' \
-H 'Content-type:application/json' \
--data-binary '["_geo"]'
每當您更新 filterableAttributes
時,Meilisearch 都會重建您的索引。根據您的資料集大小,這可能需要相當長的時間。
您可以在我們專用的篩選指南中閱讀更多關於設定 filterableAttributes
的資訊。
使用方式
使用 filter
搜尋參數 以及 _geoRadius
或 _geoBoundingBox
。這些是特殊的篩選規則,可確保 Meilisearch 只返回位於特定地理區域內的結果。
_geoRadius
_geoRadius
基於中心點和半徑建立一個圓形區域。此篩選規則需要三個參數:lat
、lng
和 distance_in_meters
。
_geoRadius(lat, lng, distance_in_meters)
lat
和 lng
必須是表示地理位置的浮點數。distance_in_meters
必須是一個整數,表示 _geoRadius
篩選器涵蓋的半徑。
_geoBoundingBox
_geoBoundingBox
基於其右上角和左下角的坐標建立一個矩形區域。此篩選規則需要兩個陣列
_geoBoundingBox([{lat}, {lng}], [{lat}, {lng}])
lat
和 lng
必須是表示地理位置的浮點數。第一個陣列表示矩形區域右上角的地理坐標。第二個陣列表示矩形區域左下角的坐標。
範例
使用我們的範例資料集,我們可以搜尋米蘭市中心附近的用餐地點,使用 _geoRadius
curl \
-X POST 'https://127.0.0.1:7700/indexes/restaurants/search' \
-H 'Content-type:application/json' \
--data-binary '{ "filter": "_geoRadius(45.472735, 9.184019, 2000)" }'
我們也使用 _geoBoundingBox
執行類似的查詢
curl \
-X POST 'https://127.0.0.1:7700/indexes/restaurants/search' \
-H 'Content-type:application/json' \
--data-binary '{ "filter": "_geoBoundingBox([45.494181, 9.214024], [45.449484, 9.179175])" }'
在這兩種情況下,結果應該如下所示
[
{
"id": 1,
"name": "Nàpiz' Milano",
"address": "Viale Vittorio Veneto, 30, 20124, Milan, Italy",
"type": "pizza",
"rating": 9,
"_geo": {
"lat": 45.4777599,
"lng": 9.1967508
}
},
{
"id": 3,
"name": "Artico Gelateria Tradizionale",
"address": "Via Dogana, 1, 20123 Milan, Italy",
"type": "ice cream",
"rating": 10,
"_geo": {
"lat": 45.4632046,
"lng": 9.1719421
}
}
]
也可以將 _geoRadius
和 _geoBoundingBox
與其他篩選器結合使用。我們可以縮小之前的搜尋範圍,使其僅包含披薩店
curl \
-X POST 'https://127.0.0.1:7700/indexes/restaurants/search' \
-H 'Content-type:application/json' \
--data-binary '{ "filter": "_geoRadius(45.472735, 9.184019, 2000) AND type = pizza" }'
[
{
"id": 1,
"name": "Nàpiz' Milano",
"address": "Viale Vittorio Veneto, 30, 20124, Milan, Italy",
"type": "pizza",
"rating": 9,
"_geo": {
"lat": 45.4777599,
"lng": 9.1967508
}
}
]
如果您之前已將 type
添加到 filterableAttributes
,則上述命令才有效。
警告
_geo
、_geoDistance
和 _geoPoint
不是有效的篩選規則。嘗試將它們中的任何一個與 filter
搜尋參數一起使用,將會導致 invalid_search_filter
錯誤。
使用 _geoPoint
排序結果
您可以使用 _geo
數據來根據與特定位置的距離來排序結果。
設定
在將地理搜尋用於排序之前,您必須將 _geo
屬性添加到 sortableAttributes
清單中
curl \
-X PUT 'https://127.0.0.1:7700/indexes/restaurants/settings/sortable-attributes' \
-H 'Content-type:application/json' \
--data-binary '["_geo"]'
請注意,每當您更新 sortableAttributes
時,Meilisearch 都會重建您的索引。根據您的資料集大小,這可能需要相當長的時間。
您可以在我們專用的排序指南中閱讀更多關於設定 sortableAttributes
的資訊。
使用方式
首先,請確保您的文件包含有效的地理位置數據,並且您已將 _geo
屬性添加到 sortableAttributes
清單中。然後,您可以使用 sort
搜尋參數 以及 _geoPoint
,這是一個特殊的排序函數,用於根據與地理位置的距離來排序結果。
_geoPoint(0.0, 0.0):asc
_geoPoint
需要兩個表示位置緯度和經度的浮點數。您還必須指定排序應該是升序 (asc
) 還是降序 (desc
)。升序排序將優先考慮較接近指定位置的結果,而降序排序將首先顯示最遠的結果。
如果 lat
或 lng
無效或遺失,Meilisearch 將返回 invalid_search_sort
錯誤。如果您未能指示排序順序,也會拋出錯誤。
警告
_geo
、_geoDistance
和 _geoRadius
不是有效的 sort
值。嘗試將它們中的任何一個與 sort
搜尋參數一起使用,將會導致 invalid_search_sort
錯誤。
範例
_geoPoint
排序函數可以像任何其他排序規則一樣使用。我們可以根據文件與艾菲爾鐵塔的距離來排序文件
curl \
-X POST 'https://127.0.0.1:7700/indexes/restaurants/search' \
-H 'Content-type:application/json' \
--data-binary '{ "sort": ["_geoPoint(48.8561446,2.2978204):asc"] }'
使用我們的餐廳資料集,結果如下所示
[
{
"id": 2,
"name": "Bouillon Pigalle",
"address": "22 Bd de Clichy, 75018 Paris, France",
"type": "french",
"rating": 8,
"_geo": {
"lat": 48.8826517,
"lng": 2.3352748
}
},
{
"id": 3,
"name": "Artico Gelateria Tradizionale",
"address": "Via Dogana, 1, 20123 Milan, Italy",
"type": "ice cream",
"rating": 10,
"_geo": {
"lat": 45.4632046,
"lng": 9.1719421
}
},
{
"id": 1,
"name": "Nàpiz' Milano",
"address": "Viale Vittorio Veneto, 30, 20124, Milan, Italy",
"type": "pizza",
"rating": 9,
"_geo": {
"lat": 45.4777599,
"lng": 9.1967508
}
}
]
_geoPoint
在與其他排序規則一起使用時也有效。我們可以根據餐廳與艾菲爾鐵塔的距離及其評分來排序餐廳
curl \
-X POST 'https://127.0.0.1:7700/indexes/restaurants/search' \
-H 'Content-type:application/json' \
--data-binary '{
"sort": [
"_geoPoint(48.8561446,2.2978204):asc",
"rating:desc"
]
}'
如果您之前已將 rating
添加到 sortableAttributes
,則上述命令才有效。
[
{
"id": 2,
"name": "Bouillon Pigalle",
"address": "22 Bd de Clichy, 75018 Paris, France",
"type": "french",
"rating": 8,
"_geo": {
"lat": 48.8826517,
"lng": 2.3352748
}
},
{
"id": 3,
"name": "Artico Gelateria Tradizionale",
"address": "Via Dogana, 1, 20123 Milan, Italy",
"type": "ice cream",
"rating": 10,
"_geo": {
"lat": 45.4632046,
"lng": 9.1719421
}
},
{
"id": 1,
"name": "Nàpiz' Milano",
"address": "Viale Vittorio Veneto, 30, 20124, Milan, Italy",
"type": "pizza",
"rating": 9,
"_geo": {
"lat": 45.4777599,
"lng": 9.1967508
}
}
]
排名規則
預設情況下,Meilisearch 強調相關排序而不是詳盡排序。這表示我們的引擎首先找到最相關的結果,然後才根據給定給 sort
搜尋參數的值來排序符合的結果。因此,使用 _geoPoint
進行排序很少會是決定使用者首先看到哪些結果的最重要因素。更常見的是,它將成為被認為與給定搜尋查詢同等相關的結果之間的決策因素。
由於 _geoPoint
是 sort
搜尋參數的一部分,因此它在對結果進行排名時的權重由 rankingRules
陣列中 "sort"
規則的位置控制。
您可以在我們專用的排序指南中閱讀更多關於 "sort"
排名規則以及如何自訂它的資訊。
找出文件與 _geoPoint
之間的距離
當使用 _geoPoint
時,所有返回的文件都會包含一個額外的欄位:_geoDistance
。顧名思義,_geoDistance
包含指定的 _geoPoint
和文件 _geo
數據之間的距離(以公尺為單位)
[
{
"id": 1,
"name": "Nàpiz' Milano",
"address": "Viale Vittorio Veneto, 30, 20124, Milan, Italy",
"type": "pizza",
"rating": 9,
"_geo": {
"lat": 45.4777599,
"lng": 9.1967508
},
"_geoDistance": 1532
}
]
警告
使用 _geoRadius
篩選器不會導致結果包含 _geoDistance
。
只有當查詢使用 _geoPoint
和 sort
搜尋參數時,才會在返回的文件中計算 _geoDistance
。此外,只有當 _geo
出現在displayedAttributes
清單中時,返回的文件才會包含 _geoDistance
。