Elasticsearch——分詞器對String的作用
關於String型別——分詞與不分詞
在Elasticsearch中String是最基本的資料型別,如果不是數字或者標準格式的日期等這種很明顯的型別,其他的一般都會優先預設儲存成String。同樣的資料型別,Elasticsearch也提供了多種儲存與分詞的模式,不同的模式應用於不同的場景。
很多人在初次使用Elasticsearch時,都會很納悶...
- 為什麼我儲存的一句話,卻查詢不到?
- 為什麼我輸入了漢語單詞,只能一個字一個字的匹配?
- 為什麼我的url查詢不到?
等等,這些都與是否分詞、使用什麼分詞器有關。
首先說說什麼是分詞器吧! 比如我愛你中國
!
如果是標準分詞器,會把它拆分成,“我”,“愛”,“你”,“中”,“國”。
如果使用一些漢語的分詞器,則會分析成,“我”,“愛”,“你”,“中國”。
由於倒排索引都是以詞Term為索引的,因此如果分解成了一個一個的詞,查詢“中國”
的時候,中國也會被分解成“中”
,“國”
,這樣就可能誤差到”發展中國家“
這樣的詞。
再說說Elasticsearch中的分詞器吧!
不光是在索引文件(把資料匯入到Elasticsearch中),在查詢的時候也需要分詞器。只有索引和查詢的時候使用相同的分詞器,才能查詢出正確的結果。
但是有時候,我們並不想把一串String給分析,想把它當做一個完整的詞。比如
www.baidu.com
吉林省 長春市 衛星路 6543號
此時,只要設定欄位為不分析,就可以了。這時需要自定義下對映,因為預設String就是分析的,而且使用的是標準分詞器。
準備工作
先建立一個索引
curl -XPUT localhost:9200/abc
然後定義對映,注意:只有剛剛新建、還沒有任何資料的索引,才能定義對映。定義對映Mapping可以使用_mapping RESTAPI,符合下面的標準語法:
curl -XPUT localhost:9200/索引名稱/型別名稱/_mapping?pretty -d '{"型別名稱":{"properties":{"欄位名稱":{"type":"欄位型別","store":"是否儲存","index":"索引方式、是否分析"}}}}'
比如,其中str1為String型別不分析;其他的欄位str2為預設配置,就不用設定了。
curl -XPUT localhost:9200/abc/abc/_mapping?pretty -d '{"abc":{"properties":{"str1":{"type":"string","index":"not_analyzed"}}}}'
然後新增兩條資料:
curl localhost:9200/abc/abc?pretty -d '{"str1":"hello, world!","str2":"goodbye! world"}'
{
"_index" : "abc",
"_type" : "abc",
"_id" : "AVM2vRQgJmh5lL1r79nv",
"_version" : 1,
"created" : true
}
curl localhost:9200/abc/abc?pretty -d '{"str1":"hello","str2":"world"}' {
"_index" : "abc",
"_type" : "abc",
"_id" : "AVM2vbbqJmh5lL1r79nw",
"_version" : 1,
"created" : true
}
分析的String如何查詢
如果查詢的單個詞,分詞的欄位可以使用term進行查詢,如下所示:如果查詢的是一個單獨的詞,那麼會返回包含它或者等於它的目標文件。
curl -XPOST localhost:9200/abc/_search?pretty -d '{"query":{"term":{"str2":"world"}}}'
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 0.5945348,
"hits" : [ {
"_index" : "abc",
"_type" : "abc",
"_id" : "AVM2vbbqJmh5lL1r79nw",
"_score" : 0.5945348,
"_source":{"str1":"hello","str2":"world"}
}, {
"_index" : "abc",
"_type" : "abc",
"_id" : "AVM2vRQgJmh5lL1r79nv",
"_score" : 0.37158427,
"_source":{"str1":"hello, world!","str2":"goodbye! world"}
} ]
}
}
不分析的String如何查詢
如果欄位是不分詞的,而查詢的是這個欄位裡面的一個詞,那麼使用term時無法查詢到目標文件的。
$ curl -XPOST localhost:9200/abc/_search?pretty -d '{"query":{"term":{"str1":"hello"}}}'
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : 1.0,
"hits" : [ {
"_index" : "abc",
"_type" : "abc",
"_id" : "AVM2vbbqJmh5lL1r79nw",
"_score" : 1.0,
"_source":{"str1":"hello","str2":"world"}
} ]
}
}
使用term查詢,如果該欄位是不分詞,只有完整的輸入目標欄位,才能正確的匹配。
curl -XPOST localhost:9200/abc/_search?pretty -d '{"query":{"term":{"str1":"hello, world!"}}}'
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : 1.0,
"hits" : [ {
"_index" : "abc",
"_type" : "abc",
"_id" : "AVM2vRQgJmh5lL1r79nv",
"_score" : 1.0,
"_source":{"str1":"hello, world!","str2":"goodbye! world"}
} ]
}
}
總結
對於分詞的欄位:
1 如果查詢的是單個詞,則查詢到包含它的文件,返回結果與匹配程度有關
2 如果查詢的是一段能被分析的話,比如hello world
。那麼查詢的結果是包含分析得出的詞的文件,即包含hello
和world
的全部文件。
對於不分詞的欄位:
只有查詢的是 目標欄位的精確值,才能匹配。