贷前系统ElasticSearch实践总结

2020-05-29 00:00:00 索引 查询 数据 字段 文档

贷前系统负责从进件到放款前所有业务流程的实现,其中涉及一些数据量较大、条件多样且复杂的综合查询,引入ElasticSearch主要是为了提高查询效率,并希望基于ElasticSearch快速实现一个简易的数据仓库,提供一些OLAP相关功能。本文将介绍贷前系统ElasticSearch的实践经验。

一、索引

描述:为快速定位数据而设计的某种数据结构。

索引好比是一本书前面的目录,能加快数据库的查询速度。了解索引的构造及使用,对理解ES的工作模式有非常大的帮助。

常用索引:

  • 位图索引
  • 哈希索引
  • BTREE索引
  • 倒排索引

1.1 位图索引(BitMap)

位图索引适用于字段值为可枚举的有限个数值的情况。

位图索引使用二进制的数字串(bitMap)标识数据是否存在,1标识当前位置(序号)存在数据,0则表示当前位置没有数据。

下图1 为用户表,存储了性别和婚姻状况两个字段;

图2中分别为性别和婚姻状态建立了两个位图索引。

例如:性别->男 对应索引为:101110011,表示第1、3、4、5、8、9个用户为男性。其他属性以此类推。



使用位图索引查询:

  • 男性 并且已婚 的记录 = 101110011 & 11010010 = 100100010,即第1、4、8个用户为已婚男性。
  • 女性 或者未婚的记录 = 010001100 | 001010100 = 011011100, 即第2、3、5、6、7个用户为女性或者未婚。

1.2 哈希索引

顾名思义,是指使用某种哈希函数实现key->value 映射的索引结构。

哈希索引适用于等值检索,通过一次哈希计算即可定位数据的位置。

下图3 展示了哈希索引的结构,与JAVA中HashMap的实现类似,是用冲突表的方式解决哈希冲突的。



1.3 BTREE索引

BTREE索引是关系型数据库常用的索引结构,方便了数据的查询操作。

BTREE: 有序平衡N阶树, 每个节点有N个键值和N+1个指针, 指向N+1个子节点。

一棵BTREE的简单结构如下图4所示,为一棵2层的3叉树,有7条数据:



以Mysql常用的InnoDB引擎为例,描述下BTREE索引的应用。

Innodb下的表都是以索引组织表形式存储的,也就是整个数据表的存储都是B+tree结构的,如图5所示。



主键索引为图5的左半部分(如果没有显式定义自主主键,就用不为空的索引来做聚簇索引,如果也没有索引,则innodb内部会自动生成6字节的隐藏主键来做聚簇索引),叶子节点存储了完整的数据行信息(以主键 + row_data形式存储)。

二级索引也是以B+tree的形式进行存储,图5右半部分,与主键不同的是二级索引的叶子节点存储的不是行数据,而是索引键值和对应的主键值,由此可以推断出,二级索引查询多了一步查找数据主键的过程。

维护一颗有序平衡N叉树,比较复杂的就是当插入节点时节点位置的调整,尤其是插入的节点是随机无序的情况;而插入有序的节点,节点的调整只发生了整个树的局部,影响范围较小,效率较高。

可以参考红黑树的节点的插入算法:

en.wikipedia.org/wiki/R

因此如果innodb表有自增主键,则数据写入是有序写入的,效率会很高;如果innodb表没有自增的主键,插入随机的主键值,将导致B+tree的大量的变动操作,效率较低。这也是为什么会建议innodb表要有无业务意义的自增主键,可以大大提高数据插入效率。

注:

  • Mysql Innodb使用自增主键的插入效率高。
  • 使用类似Snowflake的ID生成算法,生成的ID是趋势递增的,插入效率也比较高。

1.4 倒排索引(反向索引)

倒排索引也叫反向索引,可以相对于正向索引进行比较理解。

正向索引反映了一篇文档与文档中关键词之间的对应关系;给定文档标识,可以获取当前文档的关键词、词频以及该词在文档中出现的位置信息,如图6 所示,左侧是文档,右侧是索引。



反向索引则是指某关键词和该词所在的文档之间的对应关系;给定了关键词标识,可以获取关键词所在的所有文档列表,同时包含词频、位置等信息,如图7所示。



反向索引(倒排索引)的单词的集合和文档的集合就组成了如图8所示的”单词-文档矩阵“,打钩的单元格表示存在该单词和文档的映射关系。



倒排索引的存储结构可以参考图9。其中词典是存放的内存里的,词典就是整个文档集合中解析出的所有单词的列表集合;每个单词又指向了其对应的倒排列表,倒排列表的集合组成了倒排文件,倒排文件存放在磁盘上,其中的倒排列表内记录了对应单词在文档中信息,即前面提到的词频、位置等信息。



下面以一个具体的例子来描述下,如何从一个文档集合中生成倒排索引。

如图10,共存在5个文档,列为文档编号,第二列为文档的文本内容。



将上述文档集合进行分词解析,其中发现的10个单词为:[谷歌,地图,之父,跳槽,Facebook,加盟,创始人,拉斯,离开,与],以个单词”谷歌“为例:首先为其赋予一个标识 ”单词ID“, 值为1,统计出文档频率为5,即5个文档都有出现,除了在第3个文档中出现2次外,其余文档都出现一次,于是就有了图11所示的倒排索引。



1.4.1 单词词典查询优化

对于一个规模很大的文档集合来说,可能包含几十万甚至上百万的不同单词,能否快速定位某个单词,这直接影响搜索时的响应速度,其中的优化方案就是为单词词典建立索引,有以下几种方案可供参考:

  • 词典Hash索引

Hash索引简单直接,查询某个单词,通过计算哈希函数,如果哈希表命中则表示存在该数据,否则直接返回空就可以;适合于完全匹配,等值查询。如图12,相同hash值的单词会放在一个冲突表中。



  • 词典BTREE索引

类似于Innodb的二级索引,将单词按照一定的规则排序,生成一个BTree索引,数据节点为指向倒排索引的指针。



  • 二分查找

同样将单词按照一定的规则排序,建立一个有序单词数组,在查找时使用二分查找法;二分查找法可以映射为一个有序平衡二叉树,如图14这样的结构。



  • FST(Finite State Transducers )实现

FST为一种有限状态转移机,FST有两个优点:1)空间占用小。通过对词典中单词前缀和后缀的重复利用,压缩了存储空间;2)查询速度快。O(len(str))的查询时间复杂度。

以插入“cat”、 “deep”、 “do”、 “dog” 、“dogs”这5个单词为例构建FST(注:必须已排序)。



如图15 终我们得到了如上一个有向无环图。利用该结构可以很方便的进行查询,如给定一个词 “dog”,我们可以通过上述结构很方便的查询存不存在,甚至我们在构建过程中可以将单词与某一数字、单词进行关联,从而实现key-value的映射。

当然还有其他的优化方式,如使用Skip List、Trie、Double Array Trie等结构进行优化,不再一一赘述。

二、ElasticSearch使用心得

下面结合贷前系统具体的使用案例,介绍ES的一些心得总结。

2.1 概况

目前使用的ES版本:5.6

官网地址:elastic.co/products/ela

ES一句话介绍:The Heart of the Elastic Stack(摘自官网)

ES的一些关键信息:

  • 2010年2月发布
  • Elasticsearch Store, Search, and Analyze
  • 丰富的Restful接口

2.2 基本概念

  • 索引(index)

ES的索引,也就是Index,和前面提到的索引并不是一个概念,这里是指所有文档的集合,可以类比为RDB中的一个数据库。

  • 文档(document)

即写入ES的一条记录,一般是JSON形式的。

  • 映射(Mapping)

文档数据结构的元数据描述,一般是JSON schema形式,可动态生成或提前预定义。

  • 类型(type)

由于理解和使用上的错误,type已不推荐使用,目前我们使用的ES中一个索引只建立了一个默认type。

  • 节点

一个ES的服务实例,称为一个服务节点。为了实现数据的安全可靠,并且提高数据的查询性能,ES一般采用集群模式进行部署。

  • 集群

多个ES节点相互通信,共同分担数据的存储及查询,这样就构成了一个集群。

  • 分片

分片主要是为解决大量数据的存储,将数据分割为若干部分,分片一般是均匀分布在各ES节点上的。需要注意:分片数量无法修改。

  • 副本

分片数据的一份完全的复制,一般一个分片会有一个副本,副本可以提供数据查询,集群环境下可以提高查询性能。

2.3 安装部署

  • JDK版本: JDK1.8
  • 安装过程比较简单,可参考官网:下载安装包 -> 解压 -> 运行
  • 安装过程遇到的坑:

ES启动占用的系统资源比较多,需要调整诸如文件句柄数、线程数、内存等系统参数,可参考下面的文档。

cnblogs.com/sloveling/p

2.4 实例讲解

下面以一些具体的操作介绍ES的使用:

2.4.1 初始化索引

初始化索引,主要是在ES中新建一个索引并初始化一些参数,包括索引名、文档映射(Mapping)、索引别名、分片数(默认:5)、副本数(默认:1)等,其中分片数和副本数在数据量不大的情况下直接使用默认值即可,无需配置。

下面举两个初始化索引的方式,一个使用基于Dynamic Template(动态模板) 的Dynamic Mapping(动态映射),一个使用显式预定义映射。

1) 动态模板 (Dynamic Template)

<p style="line-height: 2em;"><span style="font-size: 14px;">curl -X PUT http://ip:9200/loan_idx -H 'content-type: application/json' <br>    -d '{"mappings":{ "order_info":{ "dynamic_date_formats":["yyyy-MM-dd HH:mm:ss||yyyy-MM-dd],<br> "dynamic_templates":[<br> {"orderId2":{<br> "match_mapping_type":"string",<br> "match_pattern":"regex",<br> "match":"^orderId$",<br> "mapping":{<br> "type":"long"<br> }<br> }<br> },<br> {"strings_as_keywords":{<br> "match_mapping_type":"string",<br> "mapping":{<br> "type":"keyword",<br> "norms":false<br> }<br> }<br> }<br> ]<br> }<br>},<br>"aliases":{<br> "loan_alias":{}<br>}}'<br></span></p>

相关文章