Loading... # Elasticsearch(五) ## ES底层原理 ### 正排索引(doc values)与倒排索引 从广义上来说,`doc values`本质上是一个序列化的列式存储。列式存储适用于聚合、排序、脚本等操作,所有的数字、地理坐标、日志、IP和不分析(not_analyzed)字符类型都会默认开启。 倒排索引的优势在于查找包含某个项的文档,正排索引用来确定哪些项是否存在单个文档里。 ![ES记录.jpg][1] 如图,ES中有如上五条记录,我们执行语句 ``` GET product/_search { "query": { "match": { "name": "xiaomi" } }, "aggs": { "tag_agg_group": { "terms": { "field": "tags" } } } } ``` 倒排索引匹配项为 | match | term | doc | | :-: | :-: | :-: | | √ | xiaomi | 1,3,5 | | | phone | 1,4 | | | hongmi | 2,4 | | | erji | 2,3,5 | | | nfc | 5 | ![ES匹配.jpg][2] 我们预期的聚合结果为: | bucket | count | | :-: | :-: | | xingjiabi | 2 | | fashao | 2 | | buka | 1 | | menjinka | 1 | | newbee | 1 | | xuhangx | 1 | | zhiliangx | 1 | 如果使用倒排索引的实现方式为: | id | term | doc_id | | :-: | :-: | - | | 1 | xingjiabi | 1,3 | | 2 | fashao | 1,3 | | 3 | buka | 1 | | 4 | menjinka | 3 | | 5 | newbee | 5 | | 6 | xuhangx | 5 | | 7 | zhiliangx | 5 | | ... | ... | ... | | 100W | | | 可以看到,如第一条“xingjiabi”,我们直接就可以通过doc_id记录的数量来判断count的值,乍一看好像很美好,但是因为这是我们第一条就匹配中了。倒排索引的聚合每一条分组数据都需要去索引中查找一条记录,这个过程最坏的情况需要进行全表扫描,这还仅仅是一条分组数据,当数据量特别大的时候,每一条分组数据都需要去倒排索引中进行一次深度未知的扫描,效率可想而知有多低。 正排索引: doc values,为了聚合而生 ![doc value聚合.jpg][3] 如图,根据正排索引,可以直接聚合出所有的bucket以及对应的metric。 ![倒排索引与正排索引的区别.jpg][4] 1. 倒排索引的优势在于查找包含某个项的文档,即用于搜索查询。相反,正排索引的优势是确定哪些项是否在单个文档里。 2. 倒排索引和正排索引均是在index-time时创建,保存在Lucene文件中(序列化到磁盘)。 3. doc values使用非jvm内存,gc友好。 4. 不分词的field会在index-time时生成正排索引,聚合时直接使用正排索引,而分词的field在创建索引时是没有正排索引的,如果没有创建doc values的字段需要做聚合查询时,需要将fielddata设置为true。 #### fielddata 1. 与doc values不同,当没有doc values的字段需要聚合时,需要打开fielddata,然后临时在内存中建立正排索引,fielddata的构建和管理发生在JVM Heap中。 2. fielddata默认是不启用的,因为text字段比较长,一般只做关键字分词和搜索,很少拿它来进行全文匹配、聚合、排序。 3. ES采用circuit breaker(熔断)机制,避免fielddata一次性超过物理内存大小而导致内存溢出,如果触发熔断,查询会终止并返回异常。 4. fielddata使用的是JVM内存,doc values在内存不足时会保存在磁盘中,当内存充足时,会加载到内存提升性能。 ES官方建议,ES大部分是基于os cache(系统内存)来进行缓存和提升性能的,不建议用JVM内存来进行缓存,那样会导致一定的gc开销和oom问题,给JVM更少的内存,给os cache更大的内存。比如64G服务器,给JVM最多4~16G(6.25%~25%),os cache可以提升doc values和倒排索引的缓存和查询效果。 ### mget批量查询以及bulk增删改 #### mget: 批量查询 语法: ``` GET /_mget GET /<index>/_mget ``` 示例: ``` GET /_mget { "docs": [ { "_index": "product", "_id": 1 }, { "_index": "product", "_id": 2 } ] } ``` 如果查询的数据都在同一索引中,可以简化为: ``` GET product/_mget { "docs": [ { "_id": 1 }, { "_id": 2 } ] } ``` 如果都以id来进行搜索,还可以简化为: ``` GET product/_mget { "ids": [1,2] } ``` #### _source ``` GET product/_mget { "docs": [ { "_id": 1, "_source": false }, { "_id": 2, "_source": [ "name", "price" ] } ] } ``` _source用于指定结果中包含哪些字段,false表示不返回任何字段。_source中还可以指定include,包含哪些字段,和exclude,不包含哪些字段: ``` GET product/_mget { "docs": [ { "_id": 1, "_source": { "include": [ "name" ], "exclude": [ "name" ] } } ] } ``` #### bulk批量增删改(no-query) 语法格式: ``` POST /_bulk POST /<index>/_bulk {"action": {"metadata"}} {"data"} ``` 操作: - create:`PUT /index/_create/id/`,强制创建,如果指定了id,并且该id的记录已存在,会抛出异常。 - delete: 删除,ES会采用lazy delete(懒删除),实际上是改变doc的version使数据不能被检索,等到一定的时间或者version的值到达阈值的时候,才会被ES清除。 - index: 可以是创建(不指定id或指定id数据不存在),也可以是全量替换(指定id的数据已存在)。 - update: 执行partial update(全量替换,部分替换)。 示例: ``` POST /_bulk {"create":{"_index":"product2","_id":"1"}} {"name":"_bulk create1"} {"create":{"_index":"product2","_id":"11"}} {"name":"_bulk create11"} {"delete":{"_index":"product2","_id":"11"}} {"update":{"_index":"product2","_id":"1","retry_on_conflict":"3"}} {"doc":{"name":"_bulk name"}} {"index":{"_index":"product2","_id":"1"}} {"doc":{"name":"_bulk name1"}} {"index":{"_index":"product2","_id":"15"}} {"doc":{"name":"_bulk name15"}} ``` `"retry_on_conflict":"3"`表示,当发生version冲突时的重试次数,每次重试时尝试将本地version设置为ES内部版本号加1,如果指定次数内均失败,则抛出异常。 如果需要返回结果只包含报错的信息,可以使用: ``` POST /_bulk?filter_path=items.*.error ``` ### ES并发冲突问题 ES采用乐观锁的方式,解决并发冲突问题。 - 悲观锁: 各种情况都加锁,读写锁、行级锁、表级锁。使用简单,但是并发能力很低。 - 乐观锁: 并发能力高,操作麻烦,每次no-query操作都需要比对version。 ES内部会为每条记录维护一个版本号,每次no-query操作执行成功时version都会加1,如果执行no-query操作时,发现线程本地版本号小于ES内部版本号,就说明数据在此之前被修改过,重试或者抛出异常。 [1]: https://www.princelei.club/usr/uploads/2020/07/390723739.jpg [2]: https://www.princelei.club/usr/uploads/2020/07/1985610394.jpg [3]: https://www.princelei.club/usr/uploads/2020/07/1843894943.jpg [4]: https://www.princelei.club/usr/uploads/2020/07/2439217330.jpg Last modification:November 27th, 2020 at 11:11 pm © 允许规范转载