开发者社区> 铭毅天下> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

Elasticsearch全量数据增量遍历实现原理

简介: 0、需求 针对凤凰网财经版块的新闻数据和评论数据, 1个索引存储采集凤凰网财经版块的新闻数据;1个索引存储相关的财经数据评论结果。 统计: 1)某条新闻的评论数的多少? 2)某条评论属于哪条新闻? 3)当前已采集数据的所有评论、评论数汇总,按照评论数逆序排序,以便于图形化展示。
+关注继续查看

1、问题分解

1.1 数据如何存储,方案选型?

方案一:类似需求,1个索引ifeng_index存储新闻数据;1个索引ifeng_comm_index存储评论数据。

二者之间通过唯一值建立关联:评论数据中其来源新闻的唯一id值。

优点:数据分开存储,不存在交叉问题;

缺点:如果实现需求3),会非常复杂,做全局两通道的遍历和统计。


方案二:借助2.X-5.X版本ES中特有的父子文档实现。

注意:由于6.X版本以后,一个索引下只能存储一个type,所以父子文档也就不再可以使用。

所谓父子文档,可以理解为:

1)统一索引下的两个type,1个父type存储凤凰网新闻数据;1个子type存储凤凰网评论数据;

2)其中子type的Mapping定义要特殊处理;

3)其中子type的每条凤凰网评论数据都要关联唯一的父type的相关ID值。

优点:可以以相对较小的复杂度满足需求1)、2)、3)

缺点:以上方案二,ES6.X+都不再适用。

注意:

ES6.X已经移除父子文档的相关实现:http://t.cn/RE07V5A

但是转换为新的join的实现方式:http://t.cn/RE07IG1

综上分析,我是5.X的版本,采取方案二。


1.2 所需要技术支撑

1)父子文档技术

父子文档定义:

用于两个索引之间通过某一个特殊字段建立关联的场景。

在1对多的场景,尤其适用。如:1个父文档下有多个子文档。

缺点: 查询速度会比同等的嵌套查询慢5到10倍,详见:http://t.cn/ROir5rQ


父子文档实现:

建立父-子文档映射关系时只需要指定某一个文档 type 是另一个文档 type 的父亲。 该关系可以在如下两个时间点设置:1)创建索引时;2)在子文档 type 创建之前更新父文档的 mapping。


2)全局遍历技术

借助Scroll实现。之前的博文也有说明,http://t.cn/RE068mD

【scroll机制】:相对于from和size的分页来说,使用scroll可以模拟一个传统数据的游标,记录当前读取的文档信息位置。这个分页的用法,不是为了实时查询数据,而是为了一次性查询大量的数据(甚至是全部的数据)。

假设某索引下共有8个document,document中由code字段标记不同,0,1,2….8区分。


第一次scroll请求中,size设置为3,基于code升序排序,时间戳设置为1min;

第二次基于scroll_id查询,基于scroll_id查询第一次返回结果:0,1,2; 基于scroll_id查询第二次,返回结果:3,4,5; 基于scroll_id查询第三次,返回结果:6,7。

假设仍在的有效时间1min内,继续查询,返回结果:空。

若超时,继续scroll_id请求,则会返回类似如下的错误:


{

 "error": {

 "root_cause": [

 {

 "type": "search_context_missing_exception",

 "reason": "No search context found for id [79110689]"

 },

 {

 "type": "circuit_breaking_exception",

 "reason": "[parent] Data too large, data for [<transport_request>] would be [23195655038/21.6gb], which is larger than the limit of [23190280601/21.5gb]",

 "bytes_wanted": 23195655038,

 "bytes_limit": 23190280601

 },

3)增量遍历统计计数

对修改字段打flag标记,可以通过ES中update_by_query方法,对ES中数据进行更新操作。

如果:不存在flag字段,遍历到该条记录的时候,新增flag字段且flag置为1。

如果:存在flag字段,代表该条记录已经被遍历过。

这样的好处,防止数据被循环遍历。

其实:scroll机制已经预防了这一点,以防万一。


2、具体原理

2.1 scroll实现遍历DSL实现

步骤1:scroll查询。

基于特定的字段进行排序如下:


POST scroll_index/_search?scroll=1m

{

 "size": 3,

 "query": {

 "match_all": {}

 },

 "sort": {

 "code":"asc"

 }

}

返回结果:


{

 "_scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAFcOGqFllFRGNIdVQ2Ui1LaFJRblJKOWVDNkEAAAAABXDhqxZZRURjSHVUNlItS2hSUW5SSjllQzZBAAAAAAPXB3EWTllZcVhfUlNSRUN5M3NueUJ2YkVXUQAAAAAD1wd0Fk5ZWXFYX1JTUkVDeTNzbnlCdmJFV1EAAAAAA9cHchZOWVlxWF9SU1JFQ3kzc255QnZiRVdR",

 "took": 4,

 "timed_out": false,

 "_shards": {

 "total": 5,

 "successful": 5,

 "failed": 0

 },

 "hits": {

 "total": 8,

 "max_score": null,

 "hits": [

 {

 "_index": "scroll_index",

 "_type": "scroll_type",

 "_id": "0",

 "_score": null,

 "_source": {

 "code": 0

 },

 "sort": [

 0

 ]

 },

 {

 "_index": "scroll_index",

 "_type": "scroll_type",

 "_id": "1",

 "_score": null,

 "_source": {

 "code": 1

 },

 "sort": [

 1

 ]

 },

 {

 "_index": "scroll_index",

 "_type": "scroll_type",

 "_id": "2",

 "_score": null,

 "_source": {

 "code": 2

 },

 "sort": [

 2

 ]

 }

 ]

 }

}

步骤2:基于Scroll_id查询


POST /_search/scroll

{

 "scroll" : "1m",

 "scroll_id" : "DnF1ZXJ5VGhlbkZldGNoBQAAAAAFcOGqFllFRGNIdVQ2Ui1LaFJRblJKOWVDNkEAAAAABXDhqxZZRURjSHVUNlItS2hSUW5SSjllQzZBAAAAAAPXB3EWTllZcVhfUlNSRUN5M3NueUJ2YkVXUQAAAAAD1wd0Fk5ZWXFYX1JTUkVDeTNzbnlCdmJFV1EAAAAAA9cHchZOWVlxWF9SU1JFQ3kzc255QnZiRVdR"

}

步骤3:循环执行,直至遍历结束。

主要注意的时间。


2.3 增量部分java如何实现?

在延迟指定时间后以指定的间隔时间循环执行定时任务。

借助Java Timer类实现。 Timer 是一种定时器工具,用来在一个后台线程计划执行指定任务。


 public class TimerTest03 {

       Timer timer;


       public TimerTest03(){

           timer = new Timer();

           timer.schedule(new TimerTaskTest03(), 1000, 2000);

       }


       public static void main(String[] args) {

           new TimerTest03();

       }

   }


   public class TimerTaskTest03 extends TimerTask{


       @Override

       public void run() {

           Date date = new Date(this.scheduledExecutionTime());

           System.out.println("本次执行该线程的时间为:" + date);

       }

   }

2.5 父子文档的实现。

步骤1:定义索引,同常规定义索引一致。

但,要规划好父子文档,通过:type类型区分。

如,父文档的type定义为:fenghuang_type, 子文档定义为ifeng_comm_type。


PUT ifeng_index

{

 "mappings": {

   "ifeng_type": {},

   " ifeng_comm_type ": {

     "_parent": {

       "type": "fenghuang_type"

     }

   }

 }

}

步骤2:插入子文档数据。

父文档数据插入和传统导入数据方式一致。

举例如下:

PUT /ifeng_index/ifeng_comm_type/1?parent=XVFBASDE!

注意: 父子文档关联建立的关键是:在导入子文档数据的时候通过加入参数parent=父文档的_id。


步骤3:基于父文档查询子文档。

POST ifeng_index/ifeng_comm_type/_search

{

 "query": {

   "has_parent": {

     "type":  "ifeng_type",

     "query": {

       "match": {

         "title": "世锦赛-墨西哥锦标赛移动日精彩集锦"

       }

     }

   }

 }

}

步骤4:基于子文档查询父文档。

POST ifeng_index/ifeng_type/_search

{

 "query": {

   "has_child": {

     "type":  "ifeng_comm_type",

     "score_mode": "max",

     "query": {

       "match": {

         "title": "很精彩,棒极啦!"

       }

     }

   }

 }

}

步骤5: 查看索引中每个父文档下有多少个子文档

POST /ifeng_index/ifeng_type/

{

 "size": 0,

 "aggs": {

 "ifeng_key_agg": {

 "terms": {

 "field": "_key",

 "order": {

 "ifeng_comm_type": "desc"

 }

 },

 "aggs": {

 "ifeng_comm_type": {

 "children": {

 "type": "ifeng_comm_type"

 }

 }

 }

 }

 }

3、小结

通过父子文档,实现了1对多数据的关联;

通过scroll可以实现遍历操作,实现全量遍历;

通过scroll+java定时任务Timer,实现增量遍历。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
【laravel项目】@24 laralve使用elasticsearch,并获取elasticsearch的数据
【laravel项目】@24 laralve使用elasticsearch,并获取elasticsearch的数据
25 0
Elasticsearch集群工作原理
ELasticsearch作为一个分布式搜索引擎,能够出色地支持集群模式、动态水平扩容、故障转移等分布式系统特性,这是其作为全文搜索引擎首选的重要原因。 本文从零开始描述集群的配置和扩容过程,让你对Elasticsearch集群的工作原理有初步的理解。
74 0
Elasticsearch 空值处理实战指南
1、引言 实战业务场景中,经常会遇到定义空值、检索指定空值数据的情况。 这时候,当我们翻看官方文档 null_value 部分,会看到如下的描述: Accepts a string value which is substituted for any explicit null values. Defaults to null, which means the field is treated as missing. 接受一个字符串值替换所有显式的空值。默认为null,这意味着该字段被视为丢失。 A null value cannot be indexed or searched. W
127 0
记Elasticsearch安装与数据同步
记录Elasticsearch安装配置操作及Logstash数据同步
458 0
EFK教程(3) - ElasticSearch冷热数据分离
基于ElasticSearch多实例架构,实现资源合理分配、冷热数据分离
1289 0
Es使用指南之Elasticsearch文档读写模型实现原理
本文详细介绍了ElasticSearch文档的读写模型的设计思路,涉及到写模型及其异常处理、读模型及其异常处理、主备负载模型背后隐含的设计缺陷与ElasticSearch在异常情况带来的影响。
5338 0
Logstash中如何处理到ElasticSearch的数据映射
Logstash作为一个数据处理管道,提供了丰富的插件,能够从不同数据源获取用户数据,进行处理后发送给各种各样的后台。这中间,最关键的就是要对数据的类型就行定义或映射。 本文讨论的 ELK 版本为 5.5.1。
1486 0
elasticsearch java 增删改查 版本2
ElasticSearch(名称太长,后面简称ES)作为一个搜索引擎,目前可谓是如日中天,几乎和solr齐驾并驱。关于他能做什么,跟云计算有什么关系,在此不再描述。但是ES的官方文档,特别是关于java的客户端文档,真是少的可怜,甚至连个完整的增删改的示例都没有。在此,我就献丑了。 在开始讲解之前,还是先做个铺垫,为了能够有一个可以索引的模型,我们自定义了一个模型,暂时起个名称叫
3709 0
elasticsearch java 增删改查 版本1
既然是开发篇,主要以代码为主,辅助一些说明。所有的内容都是代码实际应该验证过的。 引入的头文件: import static org.elasticsearch.node.NodeBuilder.nodeBuilder; import java.io.IOException; import java.net.InetAddress; import java.util
1643 0
+关注
348
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载