Elasticsearch实战 | 必要的时候,还得空间换时间!

1、应用场景

实时数据流通过kafka后,根据业务需求,一部分直接借助kafka-connector入Elasticsearch不同的索引中。
另外一部分,则需要先做聚类、分类处理,将聚合出的分类结果存入ES集群的聚类索引中。如下图所示:
业务系统的分层结构可分为:接入层、数据处理层、数据存储层、接口层。
那么问题来了?
我们需要基于聚合(数据处理层)的结果实现检索和聚合分析操作,如何实现更快的检索和更高效的聚合分析效果呢?

2、方案选型

方案一:
只建立一个索引,aggs_index。
数据处理层的聚合结果存入ES中的指定索引,同时将每个聚合主题相关的数据存入每个document下面的某个field下。如下示意图所示:

方案一示意图

方案二:
新建两个索引:aggs_index以及aggs_detail_index。
其中:
1)aggs_index存储事件列表信息。
2)aggs_detail_index存储事件关联的文章内容信息。
如下图所示:

方案二示意图

3、方案对比

方案一优点:节省存储空间,只存储关联文章id,数据没有重复存储。
方案一缺点:检索、聚合慢,性能不能达标。
方案一后续的所有操作,都需要先遍历检索这一堆IDs,然后再进行检索、聚合分析操作。

操作实例如下(实际比这要复杂):
第一步:通过事件id,获取关联文章id列表;
第二步:基于关联文章id列表,进行检索和聚合操作。

POST  aggs_index/_search
{
  "_source": {
  "includes":[
    "title",
"abstract",
"publish_time",
"author"
    ]},
  "query":{
    "terms":{
      "_id":"["789b4cb872be00a04560d95bf13ec8f42c",
      "792d9610b03676dc5644c2ff4db372dec4",
"817f5cff3dd0ec3564d45615f940cb7437",
"....."]
    }
  }
}

步骤2当id数量很多时,会有如下的错误提示:

{
  "error": {
    "root_cause": [
      {
        "type": "too_many_clauses",
        "reason": "too_many_clauses:
        maxClauseCount is set to 1024"
      },

。。。

方案二优点:分开存储,便于一个索引中进行检索、聚合分析操作。
空间换时间,极大的提升检索效率、聚合速度。
方案二缺点:同样的数据,多存储了一份。
其对应的检索操作如下:

POST  aggs_index/_search
{
  "_source": {
  "includes":[
    "title",
"abstract",
"publish_time",
"author"
    ]},
  "query":{
    "term":{
      "topic_id":"WIAEgRbI0k9s1D2JrXPC"
    }
  }
}

是真的吗?
用事实说话:
以下响应时间的单位为:ms。
方案一要在N个(N接近10)索引,每个索引近千万级别的数据中检索。

两方案对比

两方案响应时间对比效果图

4、小结

  • 由以上图示,对比可知,方案二采取了空间换时间的策略,数据量多存储了一份,但是性能提升了10余倍。
  • 在实战开发中,我们要理性的选择存储方案,在磁盘成本日渐低廉的当下,把性能放在第一位,用户才能用的"爽“!

推荐阅读:

《深入理解 Java 内存模型》读书笔记

面试-基础篇

Spring Boot 2.0 迁移指南

SpringBoot使用Docker快速部署项目

为什么选择 Spring 作为 Java 框架?

SpringBoot RocketMQ 整合使用和监控

Spring Boot 面试的十个问题

使用 Spring Framework 时常犯的十大错误

SpringBoot Admin 使用指南

SpringBoot Kafka 整合使用

SpringBoot RabbitMQ 整合使用

使用Arthas 获取Spring ApplicationContext还原问题现场

上篇好文:

Elasticsearch索引增量统计及定时邮件实现

原文地址:https://www.cnblogs.com/springforall/p/11334539.html

时间: 2024-10-13 03:44:49

Elasticsearch实战 | 必要的时候,还得空间换时间!的相关文章

算法题:复制复杂链表之空间换时间法

说明:本文仅供学习交流,转载请标明出处,欢迎转载!  题目:复制一个复杂链表,所谓复杂链表指的是每个节点含有两个指针,一个指向单链表的下一个结点,一个指向单链表中的任意某个结点,或者该指针为空. 为了方便起见,我们将待复制的链表称为原型链表,将复制后的新链表称为复制链表,将指向下一个结点的指针定义为next指针,指向其他位置的指针定义为any指针.<剑指offer>上给出了三种解决方法:(1)常规法:(2)空间换时间法:(3)紧随复制法.书上并给出了第三种方法的实现代码.这里我根据书上的提示,

用空间换时间,内存数据库不止于快

近年来随着内存价格的下跌内存数据库正变得日益流行起来,内存数据库的性能也有了飞跃式的发展.然而很多开发人员在考虑内存数据库时只想到了速度,这无疑忽视了内存技术真正的潜力. 内存提供的不仅仅是更快的速度,它也是一种以存储空间换时间的方式.很多开发人员对于内存数据库的使用有一些疑虑,下面我们就来一一说明: 1.内存数据库运行比较快.除了快还有什么别的吗?我们知道内存的读写比硬盘快得多,所以将表全都加载到内存中就可以达到很高的读写速度.虚拟内存的大小受到交换分区的限制而通常交换分区的大小是内存的一到两

求质数数量 - 空间换时间

质数:被自己本身和1整出的数 int getPrimeCount(int value){ int count = 0; int arr[301] = {0};// 0 - is prime , 1 - is not prime int num = (int)sqrt((float)value); for(int i = 2; i <= num ; ++i){ if (!arr[i]){ for(int j = i; i * j < value; ++j){ arr[i * j] = 1; }

递归小题中的空间换时间思想

题目: 如数: 1  1  2  3   5   8   13   21  34  55 ...... 序号: 0  1  2  3   4   5   6     7    8    9 ...... 由用户输入序号,输出对应的数值. 效果: 实现代码: #include <stdio.h> int bian(int num); //static int shu[100]={1,1}; int main() { int num; while ( printf("请输入编号数:&qu

代码重构,空间换时间,dictionary 不要用object ,需明确指定类型

代码重构时,因为修改数据库成本很大,于是,可以在缓存中存储一份期待状态的数据结构: 例如,状态转换: 目标状态,中间件状态,原状态,三个状态之间转换时, 原来的逻辑是:目标状态<--中间件状态<--原状态,可以改为<原状态,中间件状态>-->目标状态, 一般情况下,服务器搭建在虚拟机上时,一般是存储位置大小不再考虑范围之内,cpu的计算能力是共享的,所以一个原则是::用"空间"换"时间",, 貌似: hashtable 和 dictio

HDU 2844 Coins (多重背包计数 空间换时间)

Coins Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 8999    Accepted Submission(s): 3623 Problem Description Whuacmers use coins.They have coins of value A1,A2,A3...An Silverland dollar. One

Cassandra 数据模型设计,根据你的查询来制定设计——反范式设计本质:空间换时间

转自:http://www.infoq.com/cn/articles/best-practice-of-cassandra-data-model-design 不要把Cassandra model想象成关系型数据库table 取而代之,应该把它想象成事一个有序的map结构. 对于一个新手来说,下面关系型数据库术语常常被对应到Cassandra模型 这种对比可以帮助我们从关系型数据库转换到非关系型数据库.但是当设计Cassandra column famiy的时候请不要这样去类比.取而代之,考虑

牺牲空间换时间的非比较排序之计数排序和基数排序

非比较排序试用于元素比较集中的序列. 1.计数排序 找出待排序的数组中最大和最小的元素 统计数组中每个值为i的元素出现的次数,存入数组C的第i项 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加) 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1 void CountSort(int *a, int size) { assert(a); int max = a[0]; int min = a[0]; for (int i = 1; i < siz

求一串数中的最值(空间换时间)

求最值 2014年9月19日 16:44:28 这只是个例子,可看明白了? 1 foreach (CircleInfo p in point) 2 { 3 //找出出现次数最多的数 4 allnum++; 5 temp = p.Diameter; 6 count[temp]++; 7 if (count[temp] > maxNum) 8 { 9 maxNum = count[temp]; 10 most = temp; 11 } 12 }