Elasticsearch让 keyword 和 term 忽略大小写

在 Elasticsearch 中处理字符串类型的数据时,如果我们想把整个数据作为一个完整的 term 存储,我们通常会将其类型( type) 设定为 keyword。而这种设定又会给我们带来麻烦,比如 Barbar两个实际都是 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的数据

查询二、查询三:查询不到数据

原因:

  1. 写入 Elasticsearch时由于字段的 type是 keyword,分词结果为原始字符串(type=string时,是转为小写创建索引的)

  2. 查询 Query 时分词默认是采用和字段写时相同的配置,因此这里也就是 keyword,这查就是直接把内容去匹配了;从而查询一可以匹配到数据,查询二、三查询不到数据;

  3. 注意: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条文档。

 

流程说明:

  1. es文档写入时由于对字段指定了 normalizer,那该字段的 term都会被做小写处理

  2. 查询时搜索词同样采用有 normalizer的配置,因此处理后的 term也是小写的

  3. 这样写入数据和搜索都忽略大小写,就得到了我们上面的结果

### Elasticsearch 中 `match` `term` 查询的区别 #### 1. 数据处理方式的不同 `term` 查询用于查找确切的术语,它不会对输入数据进行分析。因此,在索引阶段存储的数据是什么样,查询时就需要完全匹配该形式才能找到结果[^1]。相比之下,`match` 查询会在执行前自动分析所提供的文本内容。这种特性使得它可以针对已经过分析并存储为多个标记(tokens)的字段进行有效搜索[^4]。 #### 2. 字段类型的适用性差异 对于像 keyword 这样的未被分词器处理过的精确值字段来说,通常推荐使用 `term` 查询来实现精准检索需求;而对于 text 类型这样的会被默认标准分词器或其他指定分词策略拆分成若干子项后再存入倒排索引中的情况,则更适合采用能够理解这些分割单元之间关系并通过相应逻辑组合起来形成最终表达式的 `match` 或其他高级查询方法[^5]。 #### 3. 实际应用案例对比 假设有一个包含产品名称及其描述信息的商品数据库,并且我们希望找出所有名字正好等于 “Apple Watch Series 8”的记录: 如果直接运用未经修改的标准配置下的 `term` 操作符去尝试完成上述任务的话可能会遇到困难——除非原始字符串已经被事先设置成了不可再进一步分解的形式(即定义为了keyword),否则由于自然语言处理过程中不可避免的存在诸如大小写转换、去除停用词等一系列预处理动作的影响,“apple watch series 8” 可能早已被打散成单独几个独立的部分分别对应不同的词条位置了,此时单纯依靠简单的字面意义比较显然无法达到预期效果[^3]。 然而当我们改用支持内置解析功能的 `match` 版本来重新构建相同的请求参数列表之后却可以轻松解决这个问题,因为它内部会先按照既定规则把目标串切分为合适的片段然后再逐一对照可能存在的候选项集合直至发现符合条件的对象为止。 ```json // Example of a term query (exact match on keywords) { "query": { "term": { "product_name.keyword": "Apple Watch Series 8" } } } // Example of a match query (analyzed search against texts) { "query": { "match": { "product_description": "smartwatch with health monitoring features" } } } ``` 以上两个例子展示了如何根据不同业务场景选择合适的方式来进行高效的信息定位操作。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值