在 Elasticsearch 中處理字符串類型的數據時,如果我們想把整個數據作爲一個完整的 term 存儲,我們通常會將其類型( type)
設定爲 keyword
。而這種設定又會給我們帶來麻煩,比如 Bar
、bar
兩個實際都是 bar
,但當我們去搜索 bar
時卻無法返回 Bar的文檔。要解決這個問題,就需要 Normalizer
出場了!
PUT test_normalizer
{
"mappings": {
"properties": {
"foo":{
"type":"keyword"
}
}
}
}
PUT test_normalizer/_doc/1
{
"foo":"bar"
}
PUT test_normalizer/_doc/2
{
"foo":"Bar"
}
# 查詢一
GET test_normalizer/_search
{
"query": {
"match":{
"foo":"bar"
}
}
}
# 查詢二
GET test_normalizer/_search
{
"query": {
"match":{
"foo":"BAr"
}
}
}
# 查詢三
GET test_normalizer/_search
{
"query": {
"term":{
"foo":"baR"
}
}
}
結果:
查詢一:返回 id=1的數據
查詢二、查詢三:查詢不到數據
原因:
-
寫入
Elasticsearch
時由於字段的type
是keyword
,分詞結果爲原始字符串(type=string時,是轉爲小寫創建索引的) -
查詢 Query 時分詞默認是採用和字段寫時相同的配置,因此這裏也就是
keyword
,這查就是直接把內容去匹配了;從而查詢一可以匹配到數據,查詢二、三查詢不到數據; -
注意:term是代表完全匹配,即查詢的關鍵詞不會被分詞處理;
解決方案:Normalizer
DELETE test_normalizer
# 自定義 normalizer
PUT test_normalizer
{
"settings": {
"analysis": {
"normalizer": {
"lowercase": {
"type": "custom",
"filter": ["lowercase"]
}
}
}
},
"mappings": {
"properties": {
"foo": {
"type": "keyword"
},
"foo_normalizer": {
"type": "keyword",
"normalizer": "lowercase"
}
}
}
}
PUT test_normalizer/_doc/1
{
"foo": "bar",
"foo_normalizer": "bar"
}
PUT test_normalizer/_doc/2
{
"foo": "Bar",
"foo_normalizer": "Bar"
}
# 查詢三
GET test_normalizer/_search
{
"query": {
"term":{
"foo":"BaR"
}
}
}
# 查詢四
GET test_normalizer/_search
{
"query": {
"term":{
"foo_normalizer":"bAr"
}
}
}
1、normalizer是 keyword的一個屬性,可以對 keyword生成的單一 Term再做進一步的處理,比如 lowercase,即做小寫變換。使用方法和自定義分詞器有些類似。
2、我們第一步是自定義了名爲 lowercase的 normalizer,其中filter 類似自定義分詞器中的 filter ,normalizer中可可用的filtr種類很少,詳情大家可以查看官方文檔。
3、通過 normalizer屬性設定到指定字段type_normalizer中;
4、然後插入相同的2條文檔。執行發現,查詢三無結果返回,查詢四返回2條文檔。
流程說明:
-
es文檔寫入時由於對字段指定了
normalizer
,那該字段的term
都會被做小寫處理 -
查詢時搜索詞同樣採用有
normalizer
的配置,因此處理後的term
也是小寫的 -
這樣寫入數據和搜索都忽略大小寫,就得到了我們上面的結果