热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Elasticsearch内容汇总

一、Elasticsearch技术简介1.1Elasticsearch与MySQL的关系RDBMSElasticsearchTableIndex(Type)RowDocumentC

一、Elasticsearch技术简介

1.1 Elasticsearch与MySQL的关系































RDBMSElasticsearch
TableIndex(Type)
RowDocument
ColumnField
SchemaMapping
SQLDSL

1.1.1 Mapping

索引结构


1.1.2 DSL

查询语句


1.1.3 倒排索引

正排索引: 文档ID -> 文档内容

倒排索引:文档内容 -> 文档ID























文档ID文档内容
1Mastering Elasticsearch
2Elasticsearch Server
3Elasticsearch Essentials































TermCountDocumentId:Position
Elasticsearch31:1,2:0,3:0
Mastering11:0
Server12:1
Essentials13:1

倒排索引的核心组成



  • 倒排索引包含两个部分

    • 单词词典(Term Dictionary),记录所有文档的单词,记录单词到倒排列表的关联关系

      • 单词词典一般比较大,可以通过B+树或哈希拉链法实现,以满足高性能的插入与查询



    • 倒排列表(Posting List)记录了单词对应的文档结合,由倒排索引项组成

      • 倒排索引项(Posting)

        • 文档ID

        • 词频TF - 该单词在文档中出现的次数,用于相关性评分

        • 位置(Position)- 单词在文档中分词的位置。用于语句搜索(phrase query)

        • 便宜(Offset)- 记录单词的开始结束位置,实现高亮显示





























文档ID文档内容
1Mastering Elasticsearch
2Elasticsearch Server
3Elasticsearch Essentials

Posting List































DocIdTFPositionOffset
111<10,23>
210<0,13>
310<0,13>


  • Elasticsearch的JSON文档中的每个字段,都有自己的倒排索引

  • 可以指定对某些字段不做索引

    • 优点:节省存储空间

    • 缺点:字段无法被搜索




1.1.4 Lucene字典数据结构FST

常见的词典数据结构:







































名称特点
排序列表Array/List使用二分法查找,不平衡
HashMap/TreeMap性能高,内存消耗大,几乎是原始数组的三倍
Skip List跳跃表,可快速查找词语,在Lucene、Redis、HBase等均有实现。相对于TreeMap等结构,特别适合高并发场景
Trie适合英文词典,如果系统中存在大量字符串且这些字符串基本没有公共前缀,则相应的trie树将非常消耗内存
Double Array Trie适合做中文词典,内存占用小,很多分词工具均采用此算法
Ternary Search Tree三叉树,每一个node有3个节点,兼具省空间和查询快的优点
Finite State Transducers(FST)一种有限状态机,Luncene 4有开源实现,并大量使用

FST数据结构:

插入单词“cat”、”deep“、”do“、”dog“、”dogs“


1.2 Elasticsearch基本概念

高可用高扩展的分布式搜索引擎——Elasticsearch


1.2.1 节点

节点即一个Elasticsearch的实例,本质上就是一个Java进程,一台机器上可以运行多个Elasticsearch进程,但是生产环境一般建议一台机器上只运行一个Elasticsearch实例


Master-eligible节点和Master节点



  • 每个节点启动后默认就是一个Master-eligible节点,该类型节点可以参加选主流程,成为Master节点。

  • 当第一个节点启动的时候,它会将自己选举成Master节点

  • 每个节点都保存了集群的状态,但是只有Master节点可以修改集群的状态信息(如所有节点的信息、所有的索引以及其相关的Mapping、Setting信息、分片路由信息等)


Data节点和Coordinating节点



  • Data节点



    • 可以保存数据的节点,叫做Data Node。负责保存分片数据。在数据扩展上起到了至关重要的作用。



  • Coordinating节点



    • 负责接收Client的请求,将请求分发到合适的节点,最终把结果汇集到一起

    • 每个节点默认都起到了Coordinating Node的职责



  • Ingest 节点



    • 数据前置处理转换节点,支持pipeline管道设置

    • 可以使用ingest节点对数据进行过滤、转换等操作

    • 每个节点默认都起到了该职责,即在文档进入索引前做预处理




Hot节点和Warm节点

不同硬件配置的Data Node,用来实现Hot & Warm 架构,降低集群部署成本


分片

又称为主分片,用以解决数据水平扩展问题。通过主分片,可以将数据分布到集群内的所有节点之上。



  • 一个分片是一个运行Lucene的实例

  • 主分片数在索引创建时指定,后续不允许修改,除非Reindex


副本

用以解决数据高可用问题,是主分片的拷贝。



  • 副本分片数可以动态调整

  • 增加副本数,可以在一定程度上提高服务的可用性(读取的吞吐)


1.2.2 数据建模


1.2.3 水平扩展


1.2.4 写入流程

write

(1)客户端向NODE1发送写请求。

(2)NODE1使用文档ID来确定文档属于分片0,通过集群状态中的内容路由表信息获知分片0的主分片位于NODE3,因此请求被转发到NODE3上。

(3)NODE3上的主分片执行写操作。如果写入成功,则它将请求并行转发到 NODE1和NODE2的副分片上,等待返回结果。当所有的副分片都报告成功,NODE3将向协调节点报告成功,协调节点再向客户端报告成功。

在客户端收到成功响应时,意味着写操作已经在主分片和所有副分片都执行完成。

写入底层原理


1.2.5 查询流程

get流程

(1)客户端向NODE1发送读请求。

(2)NODE1使用文档ID来确定文档属于分片0,通过集群状态中的内容路由表信息获知分片0有三个副本数据,位于所有的三个节点中,此时它可以将请求发送到任意节点,这里它将请求转发到NODE2。

(3)NODE2将文档返回给 NODE1,NODE1将文档返回给客户端。


1.2.6 搜索流程

search

(1)客户端发送search请求到NODE 3。

(2)NODE 3将查询请求转发到索引的每个主分片或副分片中。

(3)每个分片在本地执行查询,并使用本地的Term/Document Frequency信息进行打分,添加结果到大小为from + size的本地有序优先队列中。

(4)每个分片返回各自优先队列中所有文档的ID和排序值给协调节点,协调节点合并这些值到自己的优先队列中,产生一个全局排序后的列表。


1.2.7 动态索引

动态索引



  • 新增加字段

    • Dynamic 设置为true时,一旦有新增字段的文档写入,Mapping也同时被更新

    • Dynamic 设置为false,Mapping不会被更新,新增字段的数据无法被索引,但是信息会出现在_source中

    • Dynamic 设置为Strict,文档写入失败



  • 对已有字段,一旦已经有数据写入,就不再支持修改字段定义

    • Lucene实现的倒排索引,一旦生成后,就不允许修改



  • 如果希望改变字段类型,使用Reindex API,重建索引

    • 因为如果修改了字段的数据类型,会导致已被索引的数据无法被搜索

    • 如果是增加新的字段,就不会有这样的影响




1.2.8 数据建模


1.2.8.1 Elasticsearch中处理关联关系



  • 对象类型

  • 嵌套对象(Nested Object)

  • 父子关联关系(Parent / Child)

  • 应用端关联


对象类型

因为Elasticsearch会把JSON打平(扁平式键值对结构),所以能够搜索到名称为”John“,年龄为31的文档,因为这些数据都能够被搜索到。(对象之间没有界限)

Object关联关系


Nested Data Type


  • Nested数据类型:允许对象数组中的对象被独立索引

  • 使用nested和properties关键字,将所有actors索引到多个分隔的文档

  • 在内部,Nested文档会被保存在两个Lucene文档中,在查询时做Join处理

如下对对象设置了“nested”类型,则不再能够搜索到”不正确的数据”了。

Nested


父子关联关系


  • 对象和Nested对象的局限性

    • 每次更新,需要重新索引整个对象(包括根对象和嵌套对象)



  • ES提供了类似关系型数据库中Join的实现。使用Join数据类型实现,可以通过维护Parent/Child的关系,从而分离两个对象

    • 父文档和子文档是两个独立的文档

    • 更新父文档无需重新索引子文档。子文档被添加,更新或者删除也不会影响到父文档和其他的子文档

    • 父文档和子文档必须在相同的分片上 -> 确保查询join的性能

    • 当指定子文档的时候,必须指定它的父文档Id -> 使用route参数保证分配到相同分片上



父子文档



























Nested ObjectParent / Child
优点文档存储在一起,读取性能高父子文档可以独立更新
缺点更新嵌套的子文档时,需要更新整个文档需要额外的内存维护关系。读取性能相对差
适用场景子文档偶尔更新,以查询为主子文档更新频繁

2.4 优化手段


2.4.1 深度分页


2.4.1.1 FROM+SIZE

这种分页方式,当FROM+SIZE > 10000的时候,Elasticsearch会报错,因为这里它有个默认分页窗口设置(当然也可以修改,一般不建议修改)。



  • ES天生就是分布式的。查询信息的时候需要从多个分片(多台机器)上拉取数据,并且ES天生就需要满足排序的需要(按照相关性算分)

  • 当一个查询: From = 990, Size = 10

    • 会在每个分片上都获取1000个文档。然后,通过Coordinating Node聚合所有结果。最后再通过排序选取前1000个文档

    • 页数越深,占用内存越多。为了避免深度分页带来的内存开销。ES有一个设定,默认限定到10000个文档。

      • Index.max.result.window





特别注意:如果你的查询没有指定from,size的话ES默认会限制为from,size=0,10。

提示:from是指偏移量,不是第几页,与MySQL的limit后的两个参数一样。(我就脑瓜子疼了很久,刚开始一直把from当页码。。)


2.4.1.2 SearchAfter



  • 避免深度分页的性能问题,可以实时获取下一页文档信息

    • 不支持指定偏移量

    • 只能继续向后偏移翻页



  • 第一步搜索需要指定sort,并且保证值是唯一的(可以通过加入_id保证唯一性)

  • 然后使用上一次查询的结果集中,最后一个文档的sort值继续进行查询

    SearchAfter

    关键点:根据提供的排序属性排序后的sort值为依据,向后继续翻页。类似于MySQL中,LIMIT 10000,30。我拿到了第9999条数据的id值,然后SELECT * FROM a WHERE id > 9999 LIMIT 30。

    特别注意:SearchAfter这种特性,很显然不支持跳页,但是它也是能够实时向后翻页的,而接下来介绍的Scoll翻页方式就不支持实时。


2.4.1.3 ScollAPI



  • 创建一个快照,有新的数据写入以后,无法被查到

  • 每次查询后,输入上一次的Scoll Id

ScollAPI

我理解和SearchAfter类似,一个是通过传递上一次的排序值,一个是通过传递上一次的Scoll值。不同的是,SearchAfter是实时的,而Scoll方式对翻页过程中有数据变更是无感知的。


分页总结

一般不建议深度分页,尽可能让业务增加时间范围,减少搜索范围,或者说直接使用另外两种,滚动分页即可。需要注意的是后两者对数据变化的感知是不一样的,具体需要根据场景来选择分页方式。

思考:Scoll是快照,即那一瞬间的快照,所以翻页是在快照中自己玩,对数据的变化无感知了,那么如果数据量很大,会不会把内存玩脱。


代码片段

PUT nested_index
{
"mappings": {
"properties": {
"actors" : {
"type" : "nested",
"properties": {
"first_name" : {"type" : "keyword"},
"last_name" : {"type" : "keyword"}
}
},
"title": {
"type" : "text",
"fields" : {"keyword": {"type" : "keyword","ignore_above":256}}
}
}
}
}
PUT nested_index/_doc/1
{
"title": "Speed",
"actors": [
{"first_name": "Keanu","last_name": "Reeves"},
{"first_name": "Dennis","last_name": "Hopper"}
]
}
POST nested_index/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"title": "Speed"
}
},
{
"nested": {
"path": "actors",
"query": {
"bool": {
"must": [
{"match": {"actors.first_name": "Keanu"}},
{"match": {"actors.last_name": "Hopper"}}
]
}
}
}
}
]
}
}
}
#指定父子关系,父亲为博客“blog”,子为评论“comment”
PUT parent_child_index
{
"mappings": {
"properties": {
"blog_comments_relation": {
"type" : "join",
"relations": { "blog": "comment"}
},
"content": {"type":"text"},
"title":{"type": "keyword"}
}
}
}
#索引父文档,确认自身身份为“blog”->父文档
PUT parent_child_index/_doc/blog1
{
"title" : "Learning Elasticsearch",
"content": "hello Elasticsearch",
"blog_comments_relation": {"name":"blog"}
}
#索引子文档,引用父文档。
PUT parent_child_index/_doc/comment1?routing=blog1
{
"comment": "I am learning ELK",
"username": "Jack",
"blog_comments_relation": {"name":"comment","parent":"blog1"}
}
PUT parent_child_index/_doc/blog2
{
"title" : "Learning Elasticsearch",
"content": "hello Elasticsearch",
"blog_comments_relation": {"name":"blog"}
}
PUT parent_child_index/_doc/comment2?routing=blog2
{
"comment": "I am learning ELK too",
"username": "Bob",
"blog_comments_relation": {"name":"comment","parent":"blog2"}
}
#查询所有文档
POST parent_child_index/_search
{}
#根据Parent Id查询
POST parent_child_index/_search
{
"query": {
"parent_id":{
"type": "comment",
"id": "blog2"
}
}
}
# Has Child查询,返回父文档
POST parent_child_index/_search
{
"query": {
"has_child": {
"type": "comment",
"query": {
"match": {
"username": "Jack"
}
}
}
}
}
# Has Parent查询,返回相关子文档
POST parent_child_index/_search
{
"query": {
"has_parent": {
"parent_type": "blog",
"query": {
"match": {
"title": "Learning Elasticsearch"
}
}
}
}
}


推荐阅读
  • 推荐系统遇上深度学习(十七)详解推荐系统中的常用评测指标
    原创:石晓文小小挖掘机2018-06-18笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值, ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • 文章目录题目:二叉搜索树中的两个节点被错误地交换。基本思想1:中序遍历题目:二叉搜索树中的两个节点被错误地交换。请在不改变其结构的情况下 ... [详细]
  • 本文介绍了如何在MySQL中将零值替换为先前的非零值的方法,包括使用内联查询和更新查询。同时还提供了选择正确值的方法。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 在数据分析工作中,我们通常会遇到这样的问题,一个业务部门由若干业务组构成,需要筛选出每个业务组里业绩前N名的业务员。这其实是一个分组排序的 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 本文介绍了使用postman进行接口测试的方法,以测试用户管理模块为例。首先需要下载并安装postman,然后创建基本的请求并填写用户名密码进行登录测试。接下来可以进行用户查询和新增的测试。在新增时,可以进行异常测试,包括用户名超长和输入特殊字符的情况。通过测试发现后台没有对参数长度和特殊字符进行检查和过滤。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
  • 006_Redis的List数据类型
    1.List类型是一个链表结构的集合,主要功能有push,pop,获取元素等。List类型是一个双端链表的结构,我们可以通过相关操作进行集合的头部或者尾部添加删除元素,List的设 ... [详细]
  • 本文讨论了Kotlin中扩展函数的一些惯用用法以及其合理性。作者认为在某些情况下,定义扩展函数没有意义,但官方的编码约定支持这种方式。文章还介绍了在类之外定义扩展函数的具体用法,并讨论了避免使用扩展函数的边缘情况。作者提出了对于扩展函数的合理性的质疑,并给出了自己的反驳。最后,文章强调了在编写Kotlin代码时可以自由地使用扩展函数的重要性。 ... [详细]
  • Redis底层数据结构之压缩列表的介绍及实现原理
    本文介绍了Redis底层数据结构之压缩列表的概念、实现原理以及使用场景。压缩列表是Redis为了节约内存而开发的一种顺序数据结构,由特殊编码的连续内存块组成。文章详细解释了压缩列表的构成和各个属性的含义,以及如何通过指针来计算表尾节点的地址。压缩列表适用于列表键和哈希键中只包含少量小整数值和短字符串的情况。通过使用压缩列表,可以有效减少内存占用,提升Redis的性能。 ... [详细]
author-avatar
陈雅杰昱宏
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有