es term&match 在text&keyword查询的

本文探讨了Elasticsearch中text和keyword字段在term和match查询中的行为差异,涉及倒排索引、分词与非分词的处理,以及精确查询与模糊查询的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里主要测试(text/keyowrd)在(term/match)搜索过程中的区别。

当一个文档被索引时,每个field(字段)都可能创建一个倒排索引,当然,也可以在创建mapping的时候,指定不索引该field。

我们用以下mapping创建索引 test1

PUT test1
{
  "mappings": {
    "properties": {
        "text_col": {
          "type": "text"
        },
		"keyword_col": {
          "type": "keyword"
        }
    }
  }
}

如需指定字段不进行索引:

PUT test2
{
  "mappings": {
    "properties": {
		"unindex_col": {
          "type": "keyword",
		  "index": false
        }
    }
  }
}

创建好test1后,写入一条记录,作为后面搜索测试用:

POST /test1/_doc/
{
  "text_col": "hello world 你好世界",
  "keyword_col": "hello world 你好世界"
}

当写入记录后,在text_col字段上会创建一个倒排索引 ["hello", "world", "你", "好", "世", "界"]

可用如下方式查看默认使用的分词器的分词结果:

GET /_analyze
{
  "analyzer": "standard",
  "text": "hello world 你好世界"
}

而 keyword_col 不进行分词,使用二进制原样存储为 ["hello world 你好世界"]

当然,也可以不使用默认的分词器,可以指定其它分词器,例:中文分词器。

以下进行查询测试:

1. term 查询 text 字段

term不会分词,比如说要搜索包含 “你好” 这个关键词的记录,会将 “你好” 作为一个整体(关键词)进行搜索。

查询关键词("你好"),查询字段(“text_col”)

1)term不会分词,所以进行搜索的仍为短语"你好";

2)text_col字段在写入记录时,被分词为 ["hello", "world", "你", "好", "世", "界"]进入倒排索引中,并且,顺序是固定的;

此时,短语 "你好" 在text_col字段的倒排索引中无法搜索到记录

GET /test1/_search 
{
  "query": {
    "term" : {
      "text_col": "你好"
    }
  }
}

查询关键词("你"),查询字段(“text_col”)

此时, "你" 在text_col字段的倒排索引中可以命中倒排索引( ["hello", "world", "你", "好", "世", "界"])中的关键词 "你",所以返回该条记录

GET /test1/_search 
{
  "query": {
    "term" : {
      "text_col": "你"
    }
  }
}

2. term 查询 keyword字段

term不会分词,keyword也不会分词,所以他们要两者完全匹配才行。

查询关键词("你好"),查询字段(“keyword_col”)

1) 由于term不分词,所以要进行查询的仍为一个整体 "你好"

2) 由于keyword不分词,所以在keyword_col字段上存储的也为一个整体 "hello world 你好世界"(整个短语未被分词,显然不等于"你好"),由于这两个短语之前并不相等,所以不会被查询出来

GET /test1/_search 
{
  "query": {
    "term" : {
      "keyword_col": "你好"
    }
  }
}

查询关键词("hello world 你好世界"),查询字段(“keyword_col”)

term 和 keyword两者都不分词,当两者完全匹配的时候,是能查出来的:

GET /test1/_search 
{
  "query": {
    "term" : {
      "keyword_col": "hello world 你好世界"
    }
  }
}

3. match 查询 text 字段

match会被分词,所以搜索的时候,要查询的关键词也会被进行分词。

text会被分词,所以写入text字段的记录会被分词后写入到倒排索引中,仅能匹配倒排索引中的分词。

查询关键词("你好")、("您好")、("hell world")、("好你"),查询字段(“text_col”)

1) match分被分词,所以 "你好" 会被分词为 ["你", "好"] 两个关键词进行查询

2) text字段会被分词,所以text_col字段的倒排索引为 ["hello", "world", "你", "好", "世", "界"]

"你" 和 “好” 两个关键词都命中了倒排索引,所以能查出结果:

GET /test1/_search 
{
  "query": {
    "match" : {
      "text_col": "你好"
    }
  }
}

当查询 “您好”时,要查询的关键词 “您好” 被分词为 ["您", "好"],其中 "好" 命中了text_col字段上的倒排索引中的 "好",所以也能查询出结果

GET /test1/_search
{
  "query": {
    "match" : {
      "text_col": "您好"
    }
  }
}

同样的,当查询 “hell world”时,要查询的关键词 “hell world” 被分词为 ["hell", "world"],其中 "world" 命中了text_col字段上的倒排索引中的 "world",所以也能查询出结果

GET /test1/_search
{
  "query": {
    "match" : {
      "text_col": "hell world"
    }
  }
}

当查询的关键词为 “好你” 时,同样能返回记录。

GET /test1/_search
{
  "query": {
    "match" : {
      "text_col": "好你"
    }
  }
}

留意一下score字段的值:

当查询 "你" 的时候,score为 0.2876821

当查询 "hello" 的时候,score为 0.2876821

当查询 "你好" 的时候,score为 0.5753642,命中了两个关键词,score正好翻了一倍

当查询 "好你" 的时候,score仍为 0.5753642

当查询 "你好呀" 的时候,score仍为 0.5753642

当查询 "你好好" 的时候,score仍为 0.8630463,"好" 的score又计算了一次

4. match 查询 keyword字段

match会被分词,所以搜索的时候,要查询的关键词也会被进行分词。

keyword不会被分词,所以keyword_col字段的值 "hello world 你好世界" 作为一个整体被存储。

查询关键词("hello world 你好世界")、("hello world 你好界世")、("你好"),查询字段(“keyword_col”)

当分词按顺序组合起来后与keyword_col字段的值一致的时候,是能查出来的

GET /test1/_search 
{
  "query": {
    "match" : {
      "keyword_col": "hello world 你好世界"
    }
  }
}

当分词的顺序不一致时,无法查询出来:

GET /test1/_search 
{
  "query": {
    "match" : {
      "keyword_col": "hello world 你好界世"
    }
  }
}

当分词只包含短语 "hello world 你好世界" 中的一部分时,无法查询出来:

GET /test1/_search 
{
  "query": {
    "match" : {
      "keyword_col": "你好"
    }
  }
}

小结:

1. term & match

term:精确查询,对查询关键字不进行分词,将要查询的关键字作为一个整体进入要查询的字段上的倒排索引上去匹配

match:模糊查询,对查询关键词先进行分词,然后将分词逐一代入要查询的字段上的倒排索引上去匹配

2. text & keyword

text:对要写入的记录进行分词,然后将分词逐一写入到对应字段上的倒排索引中

keyword:对要写入的记录不进行分词,而是将整个记录作为一个整体写入到对应字段上的倒排索引中

### 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
发出的红包

打赏作者

FightingFreedom

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值