前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Elasticsearch中keyword和numeric对性能的影响分析

Elasticsearch中keyword和numeric对性能的影响分析

作者头像
用户7634691
发布2021-02-03 12:04:33
3.1K0
发布2021-02-03 12:04:33
举报
文章被收录于专栏:犀牛饲养员的技术笔记

Elasticsearch中keyword和numeric对性能的影响分析

初学者认为这两个关键字的没啥关系,一个是用于字符串的精确匹配查询,一个是数字类型的字段用在计数的场景,比如说博客的点赞数,订单金额等。

但是有些场景似乎两个关键字都可以用,比如电商场景下的订单状态,一般我们也是用数字表示不同的状态,比如1表示待支付,2表示支付成功。第一反应是用Byte(属于numeric),没有问题。但是用keyword是否可以呢?

numeric除了支持等值精确查询,还可以范围查询。但是大部分情况下我们业务场景对于订单状态的使用都是精确查询的,不会有大于某个状态或者小于某个状态这样的情况。

所以刚才说的订单状态的场景,用keyword和numeric肯定都可以满足。但是那种方案好呢?答案是keyword。

对于keyword类型的term query,ES使用的是倒排索引。但是numeric类型为了能有效的支持范围查询,它的存储结构并不是倒排索引。

我们知道倒排索引在内存里维护了词典 (Term Dictionary)和文档列表(Postings List)的映射关系,倒排索引本身对于精确匹配查询是非常快的,直接从字典表找到term,然后就直接找到了posting list。

numeric类型从lucene6.0开始,使用了一种名为block KD tree的存储结构。

Block KD tree介绍

kd-tree(k-dimensional树的简称),是一种对k维空间中的实例点进行存储以便对其进行快速检索的树形数据结构。这种存储结构类似于mysql里的B+数,我们知道B+数这种数据结构对于范围查找的支持是非常好的。不同于mysql, Block KD tree的叶子节点存储的是一组值的集合(block),大概是512~1024个值一组。这也是为什么叫block kd tree。

Block KD tree对于范围查询,邻近搜索支持的非常好,尤其是多维空间的情况下。

看上图,每个节点有三个元素,所以这里K=3,不同于简单二叉树每个节点都是一个元素(如下面这个图)。这样就可以方便的在一个三维的空间进行范围的比较。

标准的二叉树

对于上图中的kd-tree,搜索的过程是这样的:首先和根节点比较第一项,小于往左,大于往右,第二层比较第二项,依次类推。每层参与比较的数据是不一样的。

具体的ES内部(其实是Lucene),目前的版本是基于所谓的PointValues,比如整型在Lucene内部是IntPoint类表示,还有DoublePoint等,完整的对应关系是:

代码语言:javascript
复制
Java type  Lucene class
int         IntPoint
long        LongPoint
float       FloatPoint
double      DoublePoint
byte[]      BinaryPoint

而这些PointValues是基于kd-tree存储的,根据官方文档的介绍,lucene把叶子节点在磁盘是顺序存储的,这样搜索的效率就会非常高。

为啥numeric对于term精确匹配的查询性能没有keyword好

前面我们提到了IntPoint类,这个类有三个查询方法:

代码语言:javascript
复制
//构造精确查询,内部还是调用newRangeQuery
Query newExactQuery(String field, int value)
代码语言:javascript
复制
//构造一维查询,内部是调用多维查询的方法
Query newRangeQuery(String field, int lowerValue, int upperValue)
代码语言:javascript
复制
//构造多维查询
Query newRangeQuery(String field, int[] lowerValue, int[] upperValue)

IntPoint.java

比如我们有这样一个索引:

代码语言:javascript
复制
PUT blogs 
{
  "mappings": {
    "properties": { 
      "title":    { "type": "keyword"  }, 
      "content":    { "type": "text"  }, 
      "status":     { "type": "integer"  }
    }
  }
}

如果我们基于status查询,

代码语言:javascript
复制
{
  "query": {
    "term": {
      "title": {
        "status": 2
      }
    }
  }
}

在lucene内部其实还是进行了一个2~2的范围查询。即便kd-tree的性能也很高,但是对于这种精确查询还是要到树上走一遭,而倒排索引相当于是直接在内存里就定位到了结果集的文档id。如果是bool组合查询的话,term还可以利用跳表,这点numeric字段也是做不到的。

多维查询的newRangeQuery里面是调用了PointRangeQuery类的查询方法。

引用:

•https://www.elastic.co/cn/blog/searching-numb3rs-in-5.0

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-01-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 犀牛的技术笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Block KD tree介绍
  • 为啥numeric对于term精确匹配的查询性能没有keyword好
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档