資料類型

    本文說明 Meilisearch 如何處理資料集中不同的資料類型。

    此處描述的行為僅與 Meilisearch 的內部流程有關,有助於了解分詞器的工作方式。對於大多數與 Meilisearch 內部運作無關的實際用途,文件欄位保持不變。

    字串

    字串是 Meilisearch 中索引資料的主要類型。它能夠建立要搜尋的內容。字串的處理方式如下詳述。

    字串分詞是將字串分割成稱為詞彙 (token) 的單獨詞彙列表的過程。

    字串會傳遞給分詞器,然後分成單獨的字串詞彙。詞彙就是一個

    分詞

    分詞依賴兩個主要流程來識別詞彙並將它們分成詞彙:分隔符號和字典。

    分隔符號

    分隔符號是表示一個詞在哪裡結束而另一個詞在哪裡開始的字元。例如,在使用拉丁字母的語言中,詞彙通常以空白分隔。在日語中,詞彙邊界更常以其他方式表示,例如在詞尾附加助詞,如

    Meilisearch 中有兩種分隔符號:軟分隔符號和硬分隔符號。硬分隔符號表示重要的上下文切換,例如新的句子或段落。軟分隔符號僅將一個詞與另一個詞分隔開,但不表示主題的重大變更。

    以下列表列出使用拉丁字母的語言中最常見的一些分隔符號

    如需更多分隔符號,包括其他書寫系統(如西里爾文和泰文)中使用的分隔符號,請參考此詳盡清單

    字典

    對於分詞流程,字典是應視為單一詞彙的字元組列表。在識別日語等詞彙並非總是使用分隔符號標記的語言時,字典特別有用。

    Meilisearch 為其官方支援的語言提供許多通用字典。在處理包含許多特定領域詞彙(如法律文件或學術論文)的文件時,提供自訂字典可能會提高搜尋結果的相關性。

    距離

    距離在決定文件是否相關方面起著至關重要的作用,因為排名規則之一是鄰近度規則。鄰近度規則會按照匹配的查詢詞彙之間距離的增加來排序結果。然後,以軟空白分隔的兩個詞比以硬空白分隔的兩個詞更接近,因此被認為更相關

    在分詞流程之後,每個詞彙都會被索引並儲存在相應索引的整體字典中。

    範例

    為了示範如何使用空白分隔字串,假設您的輸入為以下字串

    "Bruce Willis,Vin Diesel"
    

    在上面的範例中,BruceWillis 之間的距離等於 1VinDiesel 之間的距離也為 1。但是,WillisVin 之間的距離等於 8。相同的計算適用於 BruceDiesel (10)、BruceVin (9),以及 WillisDiesel (9)。

    讓我們來看另一個範例。給定兩個文件

    [
      {
        "movie_id": "001",
        "description": "Bruce.Willis"
      },
      {
        "movie_id": "002",
        "description": "Bruce super Willis"
      }
    ]
    

    當對 Bruce Willis 進行查詢時,會先傳回文件 002,然後再傳回 001。之所以會這樣,是因為在文件 002 中,BruceWillis 之間的鄰近度距離等於 2,而在文件 001 中,BruceWillis 之間的距離等於 8,因為句點字元 . 是硬空白。

    數值

    數值類型(integerfloat)會轉換為人類可讀的十進位數字字串表示。數值類型在轉換為字串後可以搜尋。

    您可以新增自訂排名規則,以在文件中具有數值的指定屬性上建立遞增或遞減排序規則。

    您也可以建立篩選器>>=<<=TO 關係運算子僅適用於數值。

    布林值

    布林值 (truefalse) 會被接收並轉換為小寫的人類可讀文字 (truefalse)。布林值在轉換為字串後可以搜尋。

    null

    null 類型可以推送至 Meilisearch,但不會被納入索引考量

    陣列

    陣列是值的有序列表。這些值可以是任何類型:數字、字串、布林值、物件,甚至是其他陣列。

    Meilisearch 會展平陣列並將它們串連成字串。非字串值會依照本文前面章節中的說明進行轉換。

    範例

    以下輸入

    [
      [
        "Bruce Willis",
        "Vin Diesel"
      ],
      "Kung Fu Panda"
    ]
    

    將會被處理,就好像所有元素都排列在同一層級

    "Bruce Willis. Vin Diesel. Kung Fu Panda."
    

    一旦展平上面的陣列,就會完全按照字串範例中的說明來剖析它。

    物件

    當文件欄位包含物件時,Meilisearch 會將其扁平化,並將物件的鍵和值帶到文件本身的根層級。

    請記住,此處表示的扁平化物件是內部流程的中間快照。搜尋時,傳回的文件將保持其原始結構。

    在下面的範例中,patient_name 鍵包含一個物件

    {
      "id": 0,
      "patient_name": {
        "forename": "Imogen",
        "surname": "Temult"
      }
    }
    

    在索引建立期間,Meilisearch 會使用點符號來消除巢狀欄位

    {
      "id": 0,
      "patient_name.forename": "Imogen",
      "patient_name.surname": "Temult"
    }
    

    使用點符號,無論巢狀深度如何,扁平化巢狀物件時都不會遺失任何資訊。

    假設上面的範例文件包含一個額外的物件 address,其中包含住家和工作地址,而每個地址本身也是物件。扁平化後,文件會看起來像這樣

    {
      "id": 0,
      "patient_name.forename": "Imogen",
      "patient_name.surname": "Temult",
      "address.home.street": "Largo Isarco, 2",
      "address.home.postcode": "20139",
      "address.home.city": "Milano",
      "address.work.street": "Ca' Corner Della Regina, 2215",
      "address.work.postcode": "30135",
      "address.work.city": "Venezia"
    }
    

    Meilisearch 的內部扁平化過程也會消除物件陣列中的巢狀結構。在這種情況下,值會按鍵分組。請考慮以下文件

    {
      "id": 0,
      "patient_name": "Imogen Temult",
      "appointments": [
        {
          "date": "2022-01-01",
          "doctor": "Jester Lavorre",
          "ward": "psychiatry"
        },
        {
          "date": "2019-01-01",
          "doctor": "Dorian Storm"
        }
      ]
    }
    

    扁平化後,它會看起來像這樣

    {
      "id": 0,
      "patient_name": "Imogen Temult",
      "appointments.date": [
        "2022-01-01",
        "2019-01-01"
      ],
      "appointments.doctor": [
        "Jester Lavorre",
        "Dorian Storm"
      ],
      "appointments.ward": [
        "psychiatry"
      ]
    }
    

    一旦文件內的所有物件都已扁平化,Meilisearch 將繼續按照先前章節所述處理它。例如,陣列將被扁平化,數字和布林值將被轉換為字串。

    巢狀文件查詢和子文件

    Meilisearch 沒有子文件的概念,無法執行巢狀文件查詢。在先前的範例中,當扁平化 appointments 陣列時,預約日期和醫生之間的關係會遺失

    "appointments.date": [
        "2022-01-01",
        "2019-01-01"
      ],
      "appointments.doctor": [
        "Jester Lavorre",
        "Dorian Storm"
      ],

    這可能會在搜尋期間導致意外行為。以下資料集顯示了兩位病患及其各自的預約

    [
      {
        "id": 0,
        "patient_name": "Imogen Temult",
        "appointments": [
          {
            "date": "2022-01-01",
            "doctor": "Jester Lavorre"
          }
        ]
      },
      {
        "id": 1,
        "patient_name": "Caleb Widowgast",
        "appointments": [
          {
            "date": "2022-01-01",
            "doctor": "Dorian Storm"
          },
          {
            "date": "2023-01-01",
            "doctor": "Jester Lavorre"
          }
        ]
      }
    ]
    

    以下查詢會傳回病患 01

    curl \
      -X POST 'https://127.0.0.1:7700/indexes/clinic_patients/search' \
      -H 'Content-Type: application/json' \
      --data-binary '{
        "q": "",
        "filter": "(appointments.date = 2022-01-01 AND appointments.doctor = 'Jester Lavorre')"
      }'
    

    Meilisearch 無法僅傳回在 2022-01-01Jester Lavorre 預約的病患。相反地,它會傳回與 Jester Lavorre 預約的病患,以及在 2022-01-01 預約的病患。

    解決此限制的最佳方法是重新格式化您的資料。可以透過在新的 appointmentsMerged 欄位中合併預約資料來修正上述範例,以便預約和醫生之間的關係保持完整

    [
      {
        "id": 0,
        "patient_name": "Imogen Temult",
        "appointmentsMerged": [
          "2022-01-01 Jester Lavorre"
        ]
      },
      {
        "id": 1,
        "patient_name": "Caleb Widowgast",
        "appointmentsMerged": [
          "2023-01-01 Jester Lavorre"
          "2022-01-01 Dorian Storm"
        ]
      }
    ]
    

    可能的符號化問題

    即使它的行為完全符合預期,符號化過程在某些情況下仍可能導致違反直覺的結果,例如

    "S.O.S"
    "George R. R. Martin"
    10,3
    

    對於上面的兩個字串,句點 . 會被視為硬空格。

    10,3 會被分成兩個字串—103—而不是被當作數值類型處理。