专栏首页方才编程ES系列09:Term-level queries 之 Term/Terms query

ES系列09:Term-level queries 之 Term/Terms query

带着问题学习才高效
  1. Term-level queries 与 Full text queries 的主要区别是什么?
  2. Term-level queries 有哪些查询类型?运用场景有哪些?DSL如何书写?
  3. Term-level queries 的各种查询对应到sql是怎样的

01

Term-level queries 简介

Term-level queries 术语级查询就是根据结构化数据中的精确值查找文档。

与( Full text queries)全文查询的不同之处在于,术语级查询不会分析检索词,而是匹配存储在字段中的确切术语。不知道这是什么意思?没关系,下面TeHero结合实例进行讲解。

Term-level queries系列脑图

ps:上图的xmind文件获取方式见文末!

通过上图可以看到,Term-level queries 一共有11种查询类型,标红的四种查询是我们常用的查询:term query、terms query、range query、wildcard query本文将先介绍:term query、terms query这两种查询!Let's Go!

02 数据准备

以博客的数据为例,数据结构如下:

创建 blogs_index 和 tags_index(就是tag的详情):

PUT /blogs_index
{
  "settings": {
    "index": {
      "number_of_shards": 1,
      "number_of_replicas": 1
    }
  },
  "mappings": {
    "_doc": {
      "dynamic": false,
      "properties": {
        "id": {
          "type": "integer"
        },
        "author": {
          "type": "keyword"
        },
        "title": {
          "type": "text",
          "analyzer": "ik_smart"
        },
        "tag":{
           "type": "integer"
        },
        "influence": {
          "type": "integer_range"
        },
        "createAt": {
          "type": "date"
        }
      }
    }
  }
}

PUT /tags_index
{
  "settings": {
    "index": {
      "number_of_shards": 1,
      "number_of_replicas": 1
    }
  },
  "mappings": {
    "_doc": {
      "dynamic": false,
      "properties": {
        "id": {
          "type": "integer"
        },
        "tag_name": {
          "type": "keyword"
        }
      }
    }
  }
}

批量导入数据:

POST _bulk
{"index":{"_index":"blogs_index","_type":"_doc","_id":"1"}}
{"id":1,"author":"方才兄","title":"关注我,系统学编程"}
{"index":{"_index":"blogs_index","_type":"_doc","_id":"2"}}
{"id":2,"author":"方才","title":"系统学编程,关注我"}

03 term query

核心点:检索词不会被分词,作为一个Token/term

3.1 通过实例理解

语句1:检索文档1的title字段的完整内容,发现居然检索不到文档!

POST /blogs_index/_doc/_search
{
  "query": {
    "term" : { "title" : "关注我,系统学编程" }
  }
}

语句2:只检索关键词“编程”,可以检索文档1和文档2

POST /blogs_index/_doc/_search
{
  "query": {
    "term" : { "title" : "编程" }
  }
}

3.2 分析DSL执行过程

在【ElasticSearch系列05:倒排序索引与分词Analysis】我们已经知道了es的检索过程【ps:该过程非常重要,一定要掌握,明白了这个检索过程,对于理解DSL语句非常有用】:

  • 1)对于title字段,我们使用的是ik_smart分词,所以这5条文档,得到的PostingList的Token列表为【关注】【我】【系统学】【编程】【方才】【兄】;
  • 2)因为是term查询,所以语句1检索词的Token列表就是【关注我,系统学编程】;语句2检索词的Token列表为【编程】;
  • 3)在PostingList中检索,很明显语句1等价于sql语句【where Token = “关注我,系统学编程”】;语句2等价于sql语句【where Token = “编程”】。
  • 4)所以语句1检索不到结果,语句2是可以检索到文档1和文档2的。

ps:如何知道es中文档的PostingList呢?直接使用_anlyze接口分析即可:

GET blogs_index/_analyze
{
  "text": [ "关注我,系统学编程"],
  "field": "title"
}

得到针对字段title,建立的PostingList:

{
  "tokens": [
    {
      "token": "关注",
      "start_offset": 0,
      "end_offset": 2,
      "type": "CN_WORD",
      "position": 0
    },
    {
      "token": "我",
      "start_offset": 2,
      "end_offset": 3,
      "type": "CN_CHAR",
      "position": 1
    },
    {
      "token": "系统学",
      "start_offset": 4,
      "end_offset": 7,
      "type": "CN_WORD",
      "position": 2
    },
    {
      "token": "编程",
      "start_offset": 7,
      "end_offset": 9,
      "type": "CN_WORD",
      "position": 3
    }
  ]
}

3.3 与match query的对比

1、检索会被分词的字段,match语句与term语句区别较大。

match 语句1:检索文档1的title字段的完整内容,得到文档1和文档2;

POST /blogs_index/_doc/_search
{
  "query": {
    "match" : { "title" : "关注我,系统学编程" }
  }
}

简单分析下:

  • 1)因为是match 查询,所以语句1检索词的Token列表就是【关注】【我】【系统学】【编程】;(注意和term查询时检索词的Token列表做对比【关注我,系统学编程】
  • 2)在PostingList中检索,该语句等价于sql语句【where Token in (“关注”,"我","系统学","编程")】;
  • 3)所以可以检索到文档1和文档2。

2、检索不会分词的字段:mathc语句与term语句效果一致

POST /blogs_index/_doc/_search
{
  "query": {
    "term" : { "author" : "方才兄" }
  }
}
POST /blogs_index/_doc/_search
{
  "query": {
    "match" : { "author" : "方才兄" }
  }
}

注意:match语句会对检索词分词,使用的分词器默认与被检索字段一致【对于author这个字段,type为keyword,所以哪怕使用的是match查询,检索词依然不会被分词】。上述两个语句都只能检索到文档1!

3.4 term query 的使用场景

一般用于检索不会被分词的字段,主要是类型为:integer、keyword、boolean 的字段。

比如说我们这个blogs_index中的author字段,假如我们只想看作者为“方才兄”的blog,DSL语句如下:

POST /blogs_index/_doc/_search
{
  "query": {
    "term" : { "author" : "方才兄" }
  }
}

04 terms query

4.1 等价于mysql 的 in()

比如,我想检索作者是【方才兄】和【方才】的文章:

POST /blogs_index/_doc/_search
{
  "query": {
    "terms" : { "author" : ["方才兄","方才"]}
  }
}

该语句等价于sql语句【where author in (“"方才兄","方才")】

4.2 Terms lookup mechanism——等价于mysql的联表查询

比如:有如下数据:

POST _bulk
{"index":{"_index":"blogs_index","_type":"_doc","_id":"3"}}
{"id":3,"author":"方才兄","title":"关注我,系统学编程","tag":[1,2,3]}
{"index":{"_index":"tags_index","_type":"_doc","_id":"1"}}
{"id":1,"tag_name":"这是标签1"}
{"index":{"_index":"tags_index","_type":"_doc","_id":"2"}}
{"id":2,"tag_name":"这是标签2"}
{"index":{"_index":"tags_index","_type":"_doc","_id":"3"}}
{"id":3,"tag_name":"这是标签3"}}

对于blogs_index中文档3,我们获取到了tag的idList集合,我们需要把tag的详细情况查出来:

GET /tags_index/_search
{
  "query": {
    "terms": {
      "id": {
        "index": "blogs_index",
        "type": "_doc",
        "id": "3",
        "path": "tag"
      }
    }
  }
}
参数解释:

index:从中获取术语值的索引。

type:从中获取术语值的类型。

id:用于获取术语值的文档的ID,是源字段_id,而不是我们自定义的字段id。

path:指定为获取terms过滤器实际值的路径的字段 。

使用场景:当需要terms语句包含大量术语时,从索引中的文档中获取这些术语值将是有益的。其实这种垮索引的查询方法,在实际中很难应用到,对数据结构有强制的要求,而且针对另一个index的查询条件,只能是 _id = xx,不能像sql一样随意书写where条件。

上述DSL语句等价于将sql语句【select * from tags_index where id in (1,2,3)】转化为了sql【select * from tags_index where id in (select tag from blogs_index where _id = 3)】。

下期预告:Term-level queries剩下的9种查询【关注公众号:方才编程,系统学习ES

本文分享自微信公众号 - 方才编程(ZeroTeHero),作者:TeHero

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-05-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • ES系列10:Term-level queries 之 Range query

    在学习本文之前,请先参考【ES系列09:Term-level queries 之 Term/Terms query】完成 blogs_index 索引的创建,同...

    方才编程_公众号同名
  • ElasticSearch实战系列02:中文+拼音混合检索,并高亮显示

    本文仿照QQ的用户搜索,搭建一个中文+拼音的混合检索系统,并高亮显示检索字段。全文共分为以下几部分:

    方才编程_公众号同名
  • ES实战系列01:基于SpringBoot和RestHighLevelClient 快速搭建博客搜索系统

    通过4个博客检索场景,巩固之前所学的全文搜索 Full Text Queries 和 基于词项的 Term lever Queries,同时通过组合查询的Boo...

    方才编程_公众号同名
  • ElasticSearch入门实战1

    若与
  • 云直播(CSS)“你问我答”第七季(2020.11月&12月)

    RTMP 推流所使用的默认端口号是1935 ,如果您测试时所在网络的防火墙不允许1935端口通行,就会遇到连不上服务器的问题。此时您可以通过切换网络(例如4G ...

    腾讯云视频
  • 从宽字节注入认识PDO的原理和正确使用

    随着数据库参数化查询的方式越来越普遍,SQL注入漏洞较之于以前也大大减少,而PDO作为php中最典型的预编译查询方式,使用越来越广泛。

    FB客服
  • Go教程:02-Go环境安装

    Go语言windows/.macOS/linux/raspberryPi开发环境安装是编程的第一步,也是最简单的. 现在我们就就开始安装最新的go语言开发环境....

    mojocn
  • 快速学习Maven-从私服下载 jar 包Nexus

    没有配置 nexus 之前,如果本地仓库没有,去中央仓库下载,通常在企业中会在局域网内部署一台私服服务器,有了私服本地项目首先去本地仓库找 jar,如果没有找到...

    cwl_java
  • HashSet、LinkedHashSet、HashMap

    add()方法的源码,底层是使用HashMap的put()方法实现元素的存取,HashMap的put存储元素的源码,可知要保证存储元素的唯一性依赖于元素的equ...

    HaC
  • 时间管理笔记(一)

    iOSDevLog

扫码关注云+社区

领取腾讯云代金券