資料類型
本文說明 Meilisearch 如何處理資料集中不同的資料類型。
此處描述的行為僅與 Meilisearch 的內部流程有關,有助於了解分詞器的工作方式。對於大多數與 Meilisearch 內部運作無關的實際用途,文件欄位保持不變。
字串
字串是 Meilisearch 中索引資料的主要類型。它能夠建立要搜尋的內容。字串的處理方式如下詳述。
字串分詞是將字串分割成稱為詞彙 (token) 的單獨詞彙列表的過程。
字串會傳遞給分詞器,然後分成單獨的字串詞彙。詞彙就是一個詞。
分詞
分詞依賴兩個主要流程來識別詞彙並將它們分成詞彙:分隔符號和字典。
分隔符號
分隔符號是表示一個詞在哪裡結束而另一個詞在哪裡開始的字元。例如,在使用拉丁字母的語言中,詞彙通常以空白分隔。在日語中,詞彙邊界更常以其他方式表示,例如在詞尾附加助詞,如 に
和 で
。
Meilisearch 中有兩種分隔符號:軟分隔符號和硬分隔符號。硬分隔符號表示重要的上下文切換,例如新的句子或段落。軟分隔符號僅將一個詞與另一個詞分隔開,但不表示主題的重大變更。
以下列表列出使用拉丁字母的語言中最常見的一些分隔符號
- 軟空白 (距離:1):空白、引號、
'-' | '_' | '\'' | ':' | '/' | '\\' | '@' | '"' | '+' | '~' | '=' | '^' | '*' | '#'
- 硬空白 (距離:8):
'.' | ';' | ',' | '!' | '?' | '(' | ')' | '[' | ']' | '{' | '}'| '|'
如需更多分隔符號,包括其他書寫系統(如西里爾文和泰文)中使用的分隔符號,請參考此詳盡清單。
字典
對於分詞流程,字典是應視為單一詞彙的字元組列表。在識別日語等詞彙並非總是使用分隔符號標記的語言時,字典特別有用。
Meilisearch 為其官方支援的語言提供許多通用字典。在處理包含許多特定領域詞彙(如法律文件或學術論文)的文件時,提供自訂字典可能會提高搜尋結果的相關性。
距離
距離在決定文件是否相關方面起著至關重要的作用,因為排名規則之一是鄰近度規則。鄰近度規則會按照匹配的查詢詞彙之間距離的增加來排序結果。然後,以軟空白分隔的兩個詞比以硬空白分隔的兩個詞更接近,因此被認為更相關。
在分詞流程之後,每個詞彙都會被索引並儲存在相應索引的整體字典中。
範例
為了示範如何使用空白分隔字串,假設您的輸入為以下字串
"Bruce Willis,Vin Diesel"
在上面的範例中,Bruce
和 Willis
之間的距離等於 1。Vin
和 Diesel
之間的距離也為 1。但是,Willis
和 Vin
之間的距離等於 8。相同的計算適用於 Bruce
和 Diesel
(10)、Bruce
和 Vin
(9),以及 Willis
和 Diesel
(9)。
讓我們來看另一個範例。給定兩個文件
[
{
"movie_id": "001",
"description": "Bruce.Willis"
},
{
"movie_id": "002",
"description": "Bruce super Willis"
}
]
當對 Bruce Willis
進行查詢時,會先傳回文件 002
,然後再傳回 001
。之所以會這樣,是因為在文件 002
中,Bruce
和 Willis
之間的鄰近度距離等於 2,而在文件 001
中,Bruce
和 Willis
之間的距離等於 8,因為句點字元 .
是硬空白。
數值
數值類型(integer
、float
)會轉換為人類可讀的十進位數字字串表示。數值類型在轉換為字串後可以搜尋。
您可以新增自訂排名規則,以在文件中具有數值的指定屬性上建立遞增或遞減排序規則。
您也可以建立篩選器。 >
、>=
、<
、<=
和 TO
關係運算子僅適用於數值。
布林值
布林值 (true
或 false
) 會被接收並轉換為小寫的人類可讀文字 (true
和 false
)。布林值在轉換為字串後可以搜尋。
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"
}
]
}
]
以下查詢會傳回病患 0
和 1
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-01
與 Jester 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
會被分成兩個字串—10
和 3
—而不是被當作數值類型處理。