地理搜尋

    Meilisearch 允許您根據結果的地理位置來篩選和排序結果。當您只想取得特定區域內的結果,或是想根據與特定位置的距離來排序結果時,這會非常有用。

    v0.27、v0.28 和 v0.29 中的 _geo 欄位

    由於 Meilisearch 在上述版本中允許格式不正確的 _geo 欄位,請確保 _geo 欄位遵循正確的格式。

    為了開始根據文件的地理位置來篩選和排序文件,您必須確保它們包含有效的 _geo 欄位。

    _geo 是一個保留欄位。如果您在文件中包含它,Meilisearch 會期望其值符合特定格式。

    當使用 JSON 和 NDJSON 時,_geo 必須包含一個具有兩個鍵的物件:latlng。這兩個欄位都必須包含一個浮點數或一個字串,分別表示緯度和經度。

    {"_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 基於中心點和半徑建立一個圓形區域。此篩選規則需要三個參數:latlngdistance_in_meters

    _geoRadius(lat, lng, distance_in_meters)
    

    latlng 必須是表示地理位置的浮點數。distance_in_meters 必須是一個整數,表示 _geoRadius 篩選器涵蓋的半徑。

    _geoBoundingBox

    _geoBoundingBox 基於其右上角和左下角的坐標建立一個矩形區域。此篩選規則需要兩個陣列

    _geoBoundingBox([{lat}, {lng}], [{lat}, {lng}])
    

    latlng 必須是表示地理位置的浮點數。第一個陣列表示矩形區域右上角的地理坐標。第二個陣列表示矩形區域左下角的坐標。

    範例

    使用我們的範例資料集,我們可以搜尋米蘭市中心附近的用餐地點,使用 _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)。升序排序將優先考慮較接近指定位置的結果,而降序排序將首先顯示最遠的結果。

    如果 latlng 無效或遺失,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 進行排序很少會是決定使用者首先看到哪些結果的最重要因素。更常見的是,它將成為被認為與給定搜尋查詢同等相關的結果之間的決策因素。

    由於 _geoPointsort 搜尋參數的一部分,因此它在對結果進行排名時的權重由 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

    只有當查詢使用 _geoPointsort 搜尋參數時,才會在返回的文件中計算 _geoDistance。此外,只有當 _geo 出現在displayedAttributes 清單中時,返回的文件才會包含 _geoDistance