很多剛開始學(xué)習(xí) Elasticsearch 的人經(jīng)常會(huì)混淆 text 和 keyword 字段數(shù)據(jù)類型。 它們之間的區(qū)別很簡(jiǎn)單,但非常關(guān)鍵。 在本文中,我將討論兩者之間的區(qū)別、如何使用它們、它們的行為方式以及使用哪一種。
區(qū)別
它們之間的關(guān)鍵區(qū)別在于,Elasticsearch 會(huì)在將 text 存儲(chǔ)到倒排索引之前對(duì)其進(jìn)行分析,而不會(huì)分析 keyword 類型。 分析或不分析將影響它在被查詢時(shí)的行為方式。有關(guān)文本分析的內(nèi)容,請(qǐng)閱讀 “Elasticsearch: analyzer”。
如果你剛開始學(xué)習(xí) Elasticsearch,還不知道什么是 Inverted Index 和 Analyzer,我建議你先閱讀文章 “Elasticsearch:inverted index,doc_values 及 source”。
如何使用它們
如果你將包含字符串的文檔索引到 Elasticsearch 之前沒有定義到字段的映射,Elasticsearch 將創(chuàng)建一個(gè)包含 text 和 keyword 數(shù)據(jù)類型的動(dòng)態(tài)映射。 但即使它適用于動(dòng)態(tài)映射,我建議你在索引任何文檔之前根據(jù)用例定義映射設(shè)置,以節(jié)省空間并提高寫入速度。
這些是 text?和 keyword 類型的映射設(shè)置示例,請(qǐng)注意,我將使用我之前為該示例創(chuàng)建的名為 text-vs-keyword?的索引。
keyword mapping
# Create index
PUT text-vs-keyword
# Create keyword mapping
PUT text-vs-keyword/_mapping
{
"properties": {
"keyword_field": {
"type": "keyword"
}
}
}
text mapping
# Create text mapping
PUT text-vs-keyword/_mapping
{
"properties": {
"text_field": {
"type": "text"
}
}
}
Multi Fields
PUT text-vs-keyword/_mapping
{
"properties": {
"text_and_keyword_mapping": {
"type": "text",
"fields": {
"keyword_type": {
"type":"keyword"
}
}
}
}
}
?運(yùn)行上面的三個(gè)命令之后,我們可以看到 text-vs-keyword 的 mapping 為:
GET text-vs-keyword/_mapping
上述命令的返回值為:
{
"text-vs-keyword": {
"mappings": {
"properties": {
"keyword_field": {
"type": "keyword"
},
"text_and_keyword_mapping": {
"type": "text",
"fields": {
"keyword_type": {
"type": "keyword"
}
}
},
"text_field": {
"type": "text"
}
}
}
}
}
上面顯示了三個(gè)字段,它們有不同的字段類型定義。特別值得指出的是:上面的 keyword_field 及 keyword_type 這些名稱都是開發(fā)者可以自己定義的名稱,但是在很多的情況下,我們把他們的名字都取為 keyword,如下:
{
"text-vs-keyword": {
"mappings": {
"properties": {
"keyword": {
"type": "keyword"
},
"text_and_keyword_mapping": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
},
"text_field": {
"type": "text"
}
}
}
}
}
他們是如何工作的
這兩種字段類型在倒排索引中的索引方式不同。 索引過程的差異會(huì)影響你何時(shí)對(duì) Elasticsearch 進(jìn)行查詢。
讓我們索引一個(gè)文檔,例如:
POST text-vs-keyword/_doc
{
"keyword_field": "The quick brown fox jumps over the lazy dog",
"text_field": "The quick brown fox jumps over the lazy dog"
}
上述命令將將生成如一個(gè)文檔。你可以通過如下的方式來進(jìn)行搜索:
GET text-vs-keyword/_search
{
"took": 4,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1,
"hits": [
{
"_index": "text-vs-keyword",
"_id": "fS95JoYBS2OSAePn1Qxh",
"_score": 1,
"_source": {
"keyword_field": "The quick brown fox jumps over the lazy dog",
"text_field": "The quick brown fox jumps over the lazy dog"
}
}
]
}
}
keyword
讓我們從更簡(jiǎn)單的 keyword 開始。 Elasticsearch 不會(huì)分析 Keyword 數(shù)據(jù)類型,這意味著你索引的 String 將保持原樣。
那么,對(duì)于上面的例子,倒排索引中的字符串會(huì)是什么樣子呢?
Term | count |
The quick brown fox jumps over the lazy dog |
1 |
是的,你沒看錯(cuò),就是你寫的那樣。
Text
與 keyword 字段數(shù)據(jù)類型不同,索引到 Elasticsearch 的字符串在存儲(chǔ)到倒排索引之前會(huì)經(jīng)過分詞器過程。 默認(rèn)情況下,Elasticsearch 的標(biāo)準(zhǔn)分詞器將拆分并小寫化我們索引的字符串。 你可以在 Elasticsearch 的文檔中了解有關(guān)標(biāo)準(zhǔn)分析器的更多信息。
Elasticsearch 有一個(gè) API 可以檢查文本在分析過程后的樣子,我們可以嘗試一下:
GET _analyze
{
"text": "The quick brown fox jumps over the lazy dog",
"analyzer": "standard"
}
我們可以看到如下的返回結(jié)果:
{
"tokens": [
{
"token": "the",
"start_offset": 0,
"end_offset": 3,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "quick",
"start_offset": 4,
"end_offset": 9,
"type": "<ALPHANUM>",
"position": 1
},
{
"token": "brown",
"start_offset": 10,
"end_offset": 15,
"type": "<ALPHANUM>",
"position": 2
},
{
"token": "fox",
"start_offset": 16,
"end_offset": 19,
"type": "<ALPHANUM>",
"position": 3
},
{
"token": "jumps",
"start_offset": 20,
"end_offset": 25,
"type": "<ALPHANUM>",
"position": 4
},
{
"token": "over",
"start_offset": 26,
"end_offset": 30,
"type": "<ALPHANUM>",
"position": 5
},
{
"token": "the",
"start_offset": 31,
"end_offset": 34,
"type": "<ALPHANUM>",
"position": 6
},
{
"token": "lazy",
"start_offset": 35,
"end_offset": 39,
"type": "<ALPHANUM>",
"position": 7
},
{
"token": "dog",
"start_offset": 40,
"end_offset": 43,
"type": "<ALPHANUM>",
"position": 8
}
]
}
所以根據(jù)上面的回復(fù),這就是 text_field 字段的倒排索引的樣子:
Term | Count |
---|---|
the | 1 |
quick | 1 |
brown | 1 |
fox | 1 |
jumps | 1 |
over | 1 |
the | 1 |
lazy | 1 |
dog | 1 |
與 keyword 略有不同,對(duì)吧? 但是你需要注意它在倒排索引中存儲(chǔ)的內(nèi)容,因?yàn)樗鼤?huì)主要影響查詢過程。
文本和關(guān)鍵字查詢
現(xiàn)在我們了解了 text 和 keyword 在索引時(shí)的行為方式,讓我們了解它們?cè)诒徊樵儠r(shí)的行為方式。
首先,我們必須知道字符串的查詢有兩種類型:
- Match query
- Term query
Match Query 和 Term Query 和 text?和 keyword 一樣,區(qū)別在于 Match Query 中的 query 會(huì)先解析為 terms,而 Term Query 中的 query 不會(huì)。Term query 不分析搜索詞。 Term query 僅搜索你提供的確切術(shù)語。 這意味著在搜索 text 字段時(shí),術(shù)語查詢可能返回較差的結(jié)果或沒有返回結(jié)果。
查詢 Elasticsearch 的工作原理是將查詢的詞與倒排索引中的詞進(jìn)行匹配,查詢的詞和倒排索引中的詞必須完全相同,否則匹配不上。 這意味著在索引和查詢結(jié)果中分析過的字符串和未分析過的字符串會(huì)產(chǎn)生截然不同的結(jié)果。
使用 Term Query 查詢 keyword 字段
因?yàn)樽侄螖?shù)據(jù)類型和查詢都沒有被分析,所以它們都需要完全相同才能產(chǎn)生結(jié)果。
如果我們嘗試使用完全相同的查詢:
GET text-vs-keyword/_search
{
"query": {
"term": {
"keyword_field": {
"value": "The quick brown fox jumps over the lazy dog"
}
}
}
}
上述命令返回的結(jié)果為:
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0.2876821,
"hits": [
{
"_index": "text-vs-keyword",
"_id": "fS95JoYBS2OSAePn1Qxh",
"_score": 0.2876821,
"_source": {
"keyword_field": "The quick brown fox jumps over the lazy dog",
"text_field": "The quick brown fox jumps over the lazy dog"
}
}
]
}
}
顯然之前寫入的文檔被搜索到了。如果我們嘗試一些不準(zhǔn)確的東西,即使倒排索引中有這個(gè)詞:
GET text-vs-keyword/_search
{
"query": {
"term": {
"keyword_field": {
"value": "The"
}
}
}
}
它沒有返回任何結(jié)果,因?yàn)椴樵冎械男g(shù)語與倒排索引中的任何術(shù)語都不匹配。
使用 Match Query 查詢 keyword 字段
讓我們首先嘗試使用 Match Query 對(duì)?keyword_field?查詢相同的字符串 “The quick brown fox jumps over the lazy dog”,看看會(huì)發(fā)生什么:
GET text-vs-keyword/_search
{
"query": {
"match": {
"keyword_field": "The quick brown fox jumps over the lazy dog"
}
}
}
結(jié)果應(yīng)該是:
{
"took": 0,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0.2876821,
"hits": [
{
"_index": "text-vs-keyword",
"_id": "fS95JoYBS2OSAePn1Qxh",
"_score": 0.2876821,
"_source": {
"keyword_field": "The quick brown fox jumps over the lazy dog",
"text_field": "The quick brown fox jumps over the lazy dog"
}
}
]
}
}
等等,它不應(yīng)該產(chǎn)生任何結(jié)果,因?yàn)椴樵儠r(shí),針對(duì)查詢的文字 “The quick brown fox jumps over the lazy dog” 需要進(jìn)行分詞。如果按照使用 standard 分詞器對(duì)它進(jìn)行分析,它產(chǎn)生的術(shù)語與倒排索引中的 “The quick brown fox jumps over the lazy dog” (這是一整個(gè)術(shù)語)不完全匹配,但為什么它會(huì)產(chǎn)生結(jié)果呢?
沒錯(cuò),查詢被分析是因?yàn)槲覀兪褂玫氖?Match Query,但 Elasticsearch 使用的不是 standard 分析器,而是?index-time 分析器,它被映射到 keyword 字段數(shù)據(jù)類型。 由于與 keyword 字段數(shù)據(jù)類型映射的分詞器是 keyword?Analyzer,因此 Elasticsearch 在查詢中沒有任何改變。我們嘗試使用 term analyzer 來試試:
GET _analyze
{
"analyzer": "keyword",
"text": "The quick brown fox jumps over the lazy dog"
}
上述命令將生成:
{
"tokens": [
{
"token": "The quick brown fox jumps over the lazy dog",
"start_offset": 0,
"end_offset": 43,
"type": "word",
"position": 0
}
]
}
可以見得,它就是只有一個(gè) term。
現(xiàn)在,讓我們嘗試使用 standard 分析器:
GET text-vs-keyword/_search
{
"query": {
"match": {
"keyword_field": {
"query": "The quick brown fox jumps over the lazy dog",
"analyzer": "standard"
}
}
}
}
在上面,我們定義了 analyzer。這個(gè)實(shí)際上是 search_analyer。請(qǐng)?jiān)敿?xì)閱讀 “Elasticsearch: analyzer”。上述命令將不會(huì)返回任何的結(jié)果。其原因顯而易見,查詢字符串的倒排術(shù)語和 keyword_field 字段里的術(shù)語完全不同。
使用 Term Query 查詢 text 類型
正如我們?cè)谏弦还?jié)中看到的那樣,text 類型的索引文檔將包含許多術(shù)語。 為了顯示查詢?nèi)绾闻c倒排索引中的術(shù)語匹配,讓我們嘗試兩個(gè)查詢,第一個(gè)查詢將整個(gè)句子發(fā)送到 Elasticsearch:
GET text-vs-keyword/_search
{
"query": {
"term": {
"text_field": {
"value": "The quick brown fox jumps over the lazy dog"
}
}
}
}
由于使用 Term query 時(shí),它不會(huì)對(duì)搜索的字符串 “The quick brown fox jumps over the lazy dog” 進(jìn)行任何的分詞,而 text_field 的倒排索引中沒有這么長(zhǎng)的完整術(shù)語。所以上述的查詢不會(huì)有任何的結(jié)果。
?我們?cè)龠M(jìn)行如下的查詢:
GET text-vs-keyword/_search
{
"query": {
"term": {
"text_field": "The"
}
}
}
這兩個(gè)查詢都沒有結(jié)果。
第一個(gè)查詢沒有產(chǎn)生結(jié)果,因?yàn)樵诘古潘饕校覀儚奈创鎯?chǔ)過整個(gè)句子,索引過程只存儲(chǔ)已經(jīng)從文本中分塊的術(shù)語。
第二個(gè)查詢也沒有產(chǎn)生任何結(jié)果。 索引文檔中有一個(gè)“The”,但記住分析器將單詞小寫,所以在 Inverted Index 中,它存儲(chǔ)為 the
讓我們用 the 再次嘗試 Term 查詢:
GET text-vs-keyword/_search
{
"query": {
"term": {
"text_field": "the"
}
}
}
是的! 它產(chǎn)生了一個(gè)結(jié)果,因?yàn)椴樵兊?the 與倒排索引中的 the 完全匹配。
使用 Match query 查詢 text 類型
現(xiàn)在是使用 Match Query 進(jìn)行 text 類型處理的時(shí)候了,因?yàn)樗鼤?huì)分析這兩種類型,所以很容易讓它們產(chǎn)生結(jié)果。 讓我們先嘗試兩個(gè)查詢:
- 第一個(gè)查詢會(huì)將 The 發(fā)送到 Elasticsearch,我們知道使用 term query 不會(huì)產(chǎn)生任何結(jié)果,但是 match query 呢?
- 第二個(gè)查詢將發(fā)送 the LAZ dog tripped over the QUICK brown dog,有些詞在倒排索引中,有些不在,Elasticsearch 會(huì)從中產(chǎn)生任何結(jié)果嗎?
GET text-vs-keyword/_search
{
"query": {
"match": {
"text_field": "The"
}
}
}
GET text-vs-keyword/_search
{
"query": {
"match": {
"text_field": "the LAZ dog tripped over th QUICK brown dog"
}
}
}
是的! 兩者都產(chǎn)生了結(jié)果:
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1.8339733,
"hits": [
{
"_index": "text-vs-keyword",
"_id": "fS95JoYBS2OSAePn1Qxh",
"_score": 1.8339733,
"_source": {
"keyword_field": "The quick brown fox jumps over the lazy dog",
"text_field": "The quick brown fox jumps over the lazy dog"
}
}
]
}
}
第一個(gè)查詢產(chǎn)生結(jié)果是因?yàn)椴樵冎械?The 被分析并成為與倒排索引中的完全匹配的 the。
第二個(gè)查詢,雖然并非所有術(shù)語都在倒排索引中,但仍會(huì)產(chǎn)生一個(gè)結(jié)果。 Elasticsearch 將返回一個(gè)結(jié)果,即使只有一個(gè)查詢的術(shù)語與倒排索引中的術(shù)語完全匹配。
如果你注意結(jié)果,有一個(gè) _score 字段。 有多少查詢?cè)~與倒排索引中的詞完全匹配是影響分?jǐn)?shù)的因素之一。請(qǐng)閱讀我的另外文章 “Elasticsearch:分布式計(jì)分”。
該選 text 還是 keyword 呢?
在以下情況下使用 keyword 字段數(shù)據(jù)類型:
- 你想要一個(gè)完全匹配查詢
- 你想讓 Elasticsearch 像其他數(shù)據(jù)庫(kù)一樣運(yùn)行
- 你想用它來進(jìn)行通配符查詢
在以下情況下使用 text 字段數(shù)據(jù)類型:
- 你想創(chuàng)建一個(gè)自動(dòng)完成
- 你想創(chuàng)建一個(gè)搜索系統(tǒng)
結(jié)論
了解 text 和 keyword 字段數(shù)據(jù)類型的工作原理是你想要在 Elasticsearch 中學(xué)習(xí)的內(nèi)容之一,區(qū)別看似簡(jiǎn)單但很重要。
你需要了解并選擇適合您的用例的字段數(shù)據(jù)類型,如果你需要兩種字段數(shù)據(jù)類型,則可以在創(chuàng)建映射時(shí)使用 multi fields 功能。比如在我們上面已經(jīng)創(chuàng)建的?text_and_keyword_mapping 字段。文章來源:http://www.zghlxwxcb.cn/news/detail-780431.html
最后,希望本文能幫助大家學(xué)習(xí) Elasticsearch,了解 Elasticsearch 中 text 和 keyword 字段數(shù)據(jù)類型的區(qū)別。 謝謝閱讀!文章來源地址http://www.zghlxwxcb.cn/news/detail-780431.html
到了這里,關(guān)于Elasticsearch:Text vs. Keyword - 它們之間的差異以及它們的行為方式的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!