Elasticsearch查询规则(一)match和term

本文详细介绍Elasticsearch中DSL查询的各种类型,包括term查询、match查询及其变种match_phrase和multi_match等,并通过实例说明每种查询的特点及应用场景。

es种有两种查询模式,一种是像传递URL参数一样去传递查询语句,被称为简单搜索或查询字符串(query string)搜索,比如

GET /megacorp/employee/_search //查询全部员工
GET /megacorp/employee/_search?q=last_name:Smith //查询last_name为Smith的员工

另外一种是通过DSL语句来进行查询,被称为DSL查询(Query DSL),DSL是Elasticsearch提供的一种丰富且灵活的查询语言,该语言以json请求体的形式出现,通过restful请求与Elasticsearch进行交互,本文主要讲DSL查询的一些常用规则,在介绍之前,我们先简单插入一个测试用的小例子(假设我们已经有了一个elasticsearch测试环境且装好了分词插件, 如果需要查看如何安装中文环境,可浏览我的另一篇文章Elasticsearch中文搜索环境搭建)。

 $curl -XPOST http://localhost:9200/index/doc/1 -d'{"content":"美国留给伊拉克的是个烂摊子吗","title":"标题","tags":["美国","伊拉克","烂摊子"]}'
 $curl -XPOST http://localhost:9200/index/doc/2 -d'{"content":"中国是世界上人口最多的国家","title":"中国","tags":["中国","人口"]}'
 $curl -XPOST http://localhost:9200/index/doc/3 -d'{"content":"同一个世界同一个梦想","title":"北京奥运","tags":["和平"]}'
 $curl -XPOST http://localhost:9200/index/doc/4 -d'{"content":"杭州是一个美丽的城市,欢迎来到杭州","title":"宣传","tags":["旅游","城市"]}'

检查一下我们的数据是否导入成功

$curl -XGET http://localhost:9200/index/doc/_search
{"took":1,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":4,"max_score":1.0,"hits":[{"_index":"index","_type":"doc","_id":"2","_score":1.0,"_source":{"content":"中国是世界上人口最多的国家","title":"中国","tags":["中国","人口"]}},{"_index":"index","_type":"doc","_id":"4","_score":1.0,"_source":{"content":"杭州是一个美丽的城市,欢迎来到杭州","title":"宣传","tags":["旅游","城市"]}},{"_index":"index","_type":"doc","_id":"1","_score":1.0,"_source":{"content":"美国留给伊拉克的是个烂摊子吗","title":"标题","tags":["美国","伊拉克","烂摊子"]}},{"_index":"index","_type":"doc","_id":"3","_score":1.0,"_source":{"content":"同一个世界同一个梦想","title":"北京奥运","tags":["和平"]}}]}}

ok,导入成功,接下来利用这些数据逐步介绍各种常用查询

term查询

term是代表完全匹配,也就是精确查询,搜索前不会再对搜索词进行分词,所以我们的搜索词必须是文档分词集合中的一个。比如说我们要找标题为北京奥运的所有文档

$curl -XGET http://localhost:9200/index/doc/_search?pretty -d 
'{
  "query":{
    "term":{
        "title":"北京奥运"
    }
  }
}'

将会得到如下结果

{
    "took": 1,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "failed": 0
    },
    "hits": {
    "total": 1,
    "max_score": 0.92055845,
    "hits": [
     {
        "_index": "index",
        "_type": "doc",
        "_id": "3",
        "_score": 0.92055845,
        "_source": {
           "content": "同一个世界同一个梦想",
           "title": "北京奥运",
           "tags": [
               "和平"
            ]
        }
      }
    ]
  }
}

搜索title包含北京或者奥运的,结果也一样,但是如果你搜索词为京奥,或者北京奥这样的,那么搜索结果将为空

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
      "total" : 5,
      "successful" : 5,
      "failed" : 0
  },
  "hits" : {
      "total" : 0,
      "max_score" : null,
      "hits" : [ ]
  }
}

这是因为在对文档建立索引时,会将北京奥运分词为北京奥运北京奥运,只要搜索词为这三个之一,都可以将这篇文章搜索出来,而京奥北京奥并不在分词集合里,所以无法搜索到该文档。
如果对于某个字段,你想精确匹配,即搜索什么词匹配什么词,类似sql中的=操作,比如只能通过北京奥运搜索到文档3而不想让北京奥运也搜索到,那么,你可以在建立索引阶段指定该字段为"index": "not_analyzed",此时,elasticsearch将不会对该字段的值进行分词操作,只保留全文字索引。比如本例子中的tags字段,我在建立索引时设置了"index": "not_analyzed", 搜索时,不管是指定tags为,还是,都无法将第一条结果搜索出来

$curl -XGET http://localhost:9200/index/doc/_search?pretty -d 
'{
  "query":{
    "term":{
        "tags":"美"
    }
  }
}'

搜索结果:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
      "total" : 5,
      "successful" : 5,
      "failed" : 0
  },
  "hits" : {
      "total" : 0,
      "max_score" : null,
      "hits" : [ ]
  }
}

而全词美国却可以

$curl -XGET http://localhost:9200/index/doc/_search?pretty -d 
'{
  "query":{
    "term":{
        "tags":"美国"
    }
  }
}'

搜索结果:

{
    "took" : 2,
    "timed_out" : false,
    "_shards" : {
        "total" : 5,
        "successful" : 5,
        "failed" : 0
    },
    "hits" : {
        "total" : 1,
        "max_score" : 0.30685282,
        "hits" : [ {
            "_index" : "index",
            "_type" : "doc",
            "_id" : "1",
            "_score" : 0.30685282,
            "_source" : {
                  "content" : "美国留给伊拉克的是个烂摊子吗",
                  "title" : "标题",
                  "tags" : [ "美国", "伊拉克", "烂摊子" ]
            }
      } ]
  }
}
match类查询

match查询会先对搜索词进行分词,分词完毕后再逐个对分词结果进行匹配,因此相比于term的精确搜索,match是分词匹配搜索,match搜索还有两个相似功能的变种,一个是match_phrase,一个是multi_match,接下来详细介绍一下

match

前面提到match搜索会先对搜索词进行分词,对于最基本的match搜索来说,只要搜索词的分词集合中的一个或多个存在于文档中即可,例如,当我们搜索中国杭州,搜索词会先分词为中国杭州,只要文档中包含搜索杭州任意一个词,都会被搜索到

$curl -XGET http://localhost:9200/index/doc/_search?pretty -d 
'{
    "query": {
        "match": {
            "content": "中国杭州"
        }
    }
}'

文档3正文中有杭州,文档2中有中国,因此搜索结果有两个,文档3中杭州出现两次,所以排在前面,结果如下:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
      "total" : 2,
      "max_score" : 0.99999994,
      "hits" : [ {
            "_index" : "index",
            "_type" : "doc",
            "_id" : "4",
            "_score" : 0.99999994,
            "_source" : {
                 "content" : "杭州是一个美丽的城市,欢迎来到杭州",
                "title" : "宣传",
                "tags" : [ "旅游", "城市" ]
            }
       }, {
            "_index" : "index",
            "_type" : "doc",
            "_id" : "2",
            "_score" : 0.8838835,
            "_source" : {
                  "content" : "中国是世界上人口最多的国家",
                  "title" : "中国",
                  "tags" : [ "中国", "人口" ]
            }
       } ]
    }
}

同样的,我们用match的方式搜索中国世界,那么,文档2(含有中国世界)和文档3(含有世界都会被搜索出来)。如果我们仅仅想搜索中国世界都包含的文档该怎么办呢?
其实,对于match搜索,可以按照分词后的分词集合的or或者and进行匹配,默认为or,这也是为什么我们看到前面的搜索都是只要有一个分词出现在文档中就会被搜索出来,同样的,如果我们希望是所有分词都要出现,那只要把匹配模式改成and就行了

curl -XGET http://localhost:9200/index/doc/_search?pretty -d 
'{
    "query": {
        "match": {
            "content": {
                "query": "中国世界",
                "operator": "and"
            }
        }
    }
}'

如上所示,查询时将operator设置为and,此时,就只会搜索到既包含中国,也包含世界的文档了(因返回的字段较多,后面搜索结果只展示_source中的内容)

"_source" : {
    "content" : "中国是世界上人口最多的国家",
    "title" : "中国",
    "tags" : [ "中国", "人口" ]
}
match_phrase

match_phrase为按短语搜索,这个可能先用英文来解释会直观一点(中文分词后其实已经是一个一个有具体意思的词语)。英文中以空格分词,因此分词后是一个个的单词,当想搜索类似hope so这样的短语时,你或许并不想将一些只含有hope的文档搜索出来,也不想将一些类似I hope ×××. So ××这样的搜索出来,此时,就可以用match_phrase。
match_phrase的搜索方式和match类似,先对搜索词建立索引,并要求所有分词必须在文档中出现(像不像operator为and的match查询),除此之外,还必须满足分词在文档中出现的顺序和搜索词中一致且各搜索词之间必须紧邻,因此match_phrase也可以叫做紧邻搜索。
所以,当我们搜美国留给

curl -XGET http://localhost:9200/index/doc/_search?pretty -d 
'{
  "query": {
    "match_phrase": {
        "content": "美国留给"
    }
  }
}'

能搜出文档美国留给伊拉克的是个烂摊子吗

    "_source" : {
        "content" : "美国留给伊拉克的是个烂摊子吗",
        "title" : "标题",
        "tags" : [ "美国", "伊拉克", "烂摊子" ]
    }

但是我们搜索留给美国美国伊拉克时,却没有搜索结果,因为一个顺序不对,一个不是紧邻(隔着留给)。
紧邻对于匹配度要求较高,为了减小精度增加可操作性,引入了slop参数。该参数可以指定相隔多少个词仍被算作匹配成功。如下,

curl -XGET http://localhost:9200/index/doc/_search?pretty -d 
'{
    "query": {
        "match_phrase": {
            "content": {
                "query": "美国伊拉克",
                "slop": "1"
            }
        }
    }
}'

当我们将slop设置为1时,文档1已能被搜索到。

  "_source" : {
    "content" : "美国留给伊拉克的是个烂摊子吗",
    "title" : "标题",
    "tags" : [ "美国", "伊拉克", "烂摊子" ]
  }

需要注意的是,当slop的值过大时(超出文档总分词数),那么分词数据将可以是随意的,即跟operator为and的match查询效果一样。比如我们查询

curl -XGET http://localhost:9200/index/doc/_search?pretty -d 
'{
    "query": {
        "match_phrase": {
            "content": {
                "query": "伊拉克美国",
                "slop": "12"
            }
        }
    }
}'

将会得到与上面一样的结果

multi_match

当我们想对多个字段进行匹配,其中一个字段包含分词就被文档就被搜索到时,可以用multi_match,这一部分内容我们后面再讲

<think> 首先,用户的问题是:“我想了解Elasticsearchmatchterm的区别 请问Elasticsearchmatchterm的区别”。这直接要求解释Elasticsearch中的matchterm查询的区别。 根据系统级指令,我需要使用中文回答,结构清晰,逐步解决问题,并保证回答真实可靠。指令还要求行内数学表达式用$...$,但这里不涉及数学,所以不需要。独立公式用$$...$$,但同样不适用。LaTeX语法正确,但查询不是数学公式。生成相关问题,并在回答末尾添加引用标识。 用户提供了几个引用源: - 引用[1]:解释了term是完全匹配、精确查询,而match是模糊匹配、分词查询。 - 引用[2]:term用于精确匹配,不分词;match会分词。给出了例子。 - 引用[3]:term精确查询match模糊查询,并强调分词处理。 - 引用[4]:match会分词,term不会;match可能匹配多个词,而term匹配整个词。 这些引用都致地描述了区别:term是精确匹配(不分词),而match是模糊匹配(分词)。 我的回答应该基于这些引用,确保真实可靠。结构上,我需要清晰、逐步地解释区别。 大纲回答结构: 1. **引言**:简要介绍matchterm查询Elasticsearch中的作用。 2. **区别总结**: - **term查询**:精确匹配,不进行分词。适用于关键词、数值等。 - **match查询**:模糊匹配,先分词再匹配。适用于文本搜索。 3. **详细解释**: - 使用示例或场景来说明。 - 引用中的关键点:term不分词,直接匹配;match分词后匹配。 4. **例子**:提供简单的查询示例来演示区别。 5. **注意事项**:如match如何使用分词器,term在keyword字段上的使用等。 6. **相关问题**:根据指令,生成相关问题,放在最后。 引用标识:在回答末尾自然地添加引用标识,例如[^1],引用提供的来源。 生成相关问题: - 基于主题:如match_phrase的作用、如何选择查询类型、性能比较等。 具体相关问题: 1. 什么是match_phrase查询?它match查询有什么区别? 2. 在哪些场景下应该使用term查询而不是match查询? 3. Elasticsearch中分词器对match查询的影响是什么? 确保回答真实可靠:基于提供的引用,避免编造信息。 最终回答格式: - 用中文。 - 结构清晰:段落分明。 - 结尾添加引用标识,如[^1]。 - 最后列出相关问题。 </think>### Elasticsearchmatchterm查询的区别 在Elasticsearch中,`match``term`查询是两种常用的搜索方式,但它们在工作原理应用场景上有显著差异。下面我将逐步解释它们的区别,确保回答基于可靠参考源。 #### 1. **核心区别总结** - **`term`查询**: 这是种**精确匹配**方式。查询时,Elasticsearch不会对搜索词进行分词处理,而是直接与文档中的字段值进行完全匹配。类似于在字典中查找个完整单词。它适用于数值、日期、布尔值或不需要分词的字符串(如ID、邮政编码)。例如: ```json GET /index/_search { "query": { "term": { "title.keyword": "jstat命令查看jvm的GC信息1" // 精确匹配整个字符串 } } } ``` 如果文档的字段值不是完全相同的词,查询将不返回结果[^2][^3]。 - **`match`查询**: 这是种**模糊匹配**方式。查询前,Elasticsearch会先对搜索词进行分词处理(例如拆分成单个单词),然后匹配文档中分词后的词条。类似于在文章中搜索关键词。它适用于文本内容搜索,能处理部分匹配情况。例如: ```json GET /index/_search { "query": { "match": { "title": "love China" // 分词为 "love" "China",匹配任意个 } } } ``` 这会匹配包含"love"或"China"的文档,因为分词后是"或"关系[^1][^4]。 #### 2. **详细工作机制对比** - **分词处理**: - `term`查询:**不分词**。搜索词被视为个整体,直接与字段值比较。如果字段是文本类型(text),通常需要指定`.keyword`子字段来避免分词影响。 - `match`查询:**先分词**。搜索词通过分词器(如standard analyzer)拆分成词条(tokens),然后与文档中的分词匹配。匹配基于词条的出现频率位置计算相关性得分。 - **匹配逻辑**: - `term`查询:要求**完全致**。例如搜索`"John Doe"`时,只匹配字段值完全为"John Doe"的文档,不会匹配包含"John"或"Doe"的文档[^2]。 - `match`查询:允许**部分匹配**。分词后,默认使用"或"逻辑(OR),匹配任意词条即可。可以通过参数调整为"与"逻辑(AND),要求所有词条都出现。例如搜索`"love China"`,如果文档包含"love""China"两个词,则匹配;但如果文档只有"love"或只有"China",也可能匹配[^4]。 - **适用场景**: - **使用`term`的场景**:精确值搜索,如用户ID、状态码、枚举类型。例如过滤订单状态为"paid"的文档。 - **使用`match`的场景**:全文搜索,如文章内容、产品描述。例如在日志中搜索"error message"关键词。 - **性能考虑**: - `term`查询通常更快,因为它无需分词,直接利用倒排索引的精确查找。 - `match`查询涉及分词相关性计算,开销较大,但更灵活,适合模糊搜索[^1][^3]。 #### 3. **实际例子说明** 假设索引中有文档: ```json { "title": "I love China" }, { "title": "Hubei province" }, { "title": "China news" } ``` - `term`查询`"China"`:无结果,因为字段值不是完全匹配"China"(如"China news"包含额外词)。 - `match`查询`"China"`:匹配所有包含"China"的文档(如"China news""I love China"),因为分词后"China"单独匹配[^3][^4]。 若需同时匹配多个词(如"love""China"),可用`match_phrase`查询代替`match`,它要求词条按顺序出现[^4]。 #### 注意事项 - **字段类型影响**:`term`查询在keyword字段上效果最佳;`match`查询适用于text字段。确保映射(mapping)正确设置。 - **相关性排序**:`match`查询默认按相关性得分排序(得分高者优先),而`term`查询无此机制。 - **组合使用**:实践中,常将`term`用于过滤,`match`用于搜索,通过`bool`查询结合两者[^1][^2]。 总之,`term`强调精确性,`match`强调灵活性。选择哪种取决于搜索需求:精确匹配用`term`,模糊搜索用`match`[^1][^2][^3][^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值