ElasticSearch笔记
前置准备
- 熟练使用Postman工具
- 了解Restful风格
简介
ElasticSearch简称ES,是一个开源的高扩展的分布式全文搜索引擎,能够安全可靠地获取任何来源、任何格式的数据,然后实时的对数据进行搜索、分析和可视化
ElasticSearch是面向文档型数据库,一条数据就是一个文档
ElasticSearch需要符合restful的请求风格
术语释义
ElasticSearch | Index(索引) | Type(类型) | Document(文档) | Fields(字段) |
MySql | DataBase(数据库) | Table(表) | Row(行) | Column(列) |
Index
- 定义:一个索引就是文档的集合,在ES集群中可以定义任意多的索引,但要注意索引的名字必须全是小写字母
- 功能:类似一本书的目录,提高搜索的性能
Type
- 5.X版本中,支持多种type
- 6.X版本中,只支持一种type
- 7.X版本中,不支持自定义索引类型,默认为_doc
Document
一个文档就是一条数据,以JSON格式表示,在一个索引中可以存储任意多的文档
Field
相当于数据库的字段,对文档的数据属性进行分类标识
Mapping
映射是处理数据的方式和规则的限制,比如某个字段的数据类型、默认值、分析器、是否被索引等等,相当于数据库中对一个字段的属性设置
Shards
分片,当一个索引的物理大小大于任意一个节点的可用磁盘空间,可以将索引划分成多份,每一份就是一个分片,每一个分片也是一个功能完善且独立的"索引",这个"索引"可以放到集群的任意一个节点上
- 优点
- 允许容量扩展
- 允许对分布式并行操作,提高性能和吞吐量
- 分片无感,和数据库的集群有点类似,查询索引时,会将查询发送到每一个分片中查询,然后合并每一个分片的结果到一个结果集中返回
Replicas
副本,用于容灾,当节点或分片因为任何原因而异常,创建的副本就有很大的作用,提高可用性,一个索引被复制之后,就有了主分片和复制分片,分片和复制的数量可以在创建索引的时候指定,创建之后可以改变复制的数量,但是一个索引的分片数量就不能被改变
Allocation
分配,将分片分配给某个节点的过程,包括分配主分片或者副本,如果是副本,还包含复制数据的过程,由master节点完成
目录结构
目录 | 含义 |
---|---|
bin | 可执行脚本目录 |
config | 配置 |
jdk | 内置JDK |
lib | 类库 |
logs | 日志目录 |
modules | 模块目录 |
plugins | 插件目录 |
启动
进入bin目录,windows执行elasticsearch.bat 文件启动ES,启动后打开浏览器访问 http://localhost:9200,看到JSON返回表示服务启动成功
Http
以下内容均使用Postman客户端工具
索引
创建索引
向ES服务发送PUT请求
http://127.0.0.1:9200/索引名 //如果重复发送请求,会报错,无法添加,因为索引唯一
查询单个索引
向ES服务发送GET请求
http://127.0.0.1:9200/索引名
查询所有索引
向ES服务发送GET请求
http://127.0.0.1:9200/_cat/indices?v //v表示返回表头
删除索引
向ES服务发送DELETE请求
http://127.0.0.1:9200/索引名
文档
创建文档
向ES服务发送POST请求
http://127.0.0.1:9200/索引名/_doc //未给数据添加唯一标识(主键)时只能发送POST请求,否则会报错
携带参数
{
"title":"大米手机",
"category":"大米",
"images":"http://www.gulixueyuan.com/xm.jpg",
"price":1999.00
}
向ES服务发送PUT/POST请求
http://127.0.0.1:9200/索引名/_doc/主键名
携带参数
{
"title":"大米手机",
"category":"大米",
"images":"http://www.gulixueyuan.com/xm.jpg",
"price":1999.00
}
查询单个文档
向ES服务发送 GET请求
http://127.0.0.1:9200/索引名/_doc/主键名 //查找不存在的主键会返回没找到
携带参数
{
"title":"大米手机",
"category":"大米",
"images":"http://www.gulixueyuan.com/xm.jpg",
"price":1999.00
}
查询全部文档
向ES服务发送GET请求
http://127.0.0.1:9200/索引名/_search
局部修改文档
向ES服务发送POST请求
http://127.0.0.1:9200/索引名/_doc/主键名
携带参数
{
"doc":{
"title":"水果手机",
"category":"水果",
}
}
全局修改文档
向ES服务发送POST请求
http://127.0.0.1:9200/索引名/_doc/主键名
携带参数
{
"title":"水果手机",
"category":"水果",
"images":"http://www.gulixueyuan.com/xm.jpg",
"price":1999.00
}
删除文档
向ES服务发送DELETE请求
http://127.0.0.1:9200/索引名/_doc/主键名 //此处的删除仅为逻辑删除
条件查询
URL带参查询
向ES服务发送GET请求
http://127.0.0.1:9200/索引名/_search?q=category:关键字
上述URL带参查询可能会出现注入或者乱码情况,建议使用带JSON请求体的GET请求进行查询,以下的请求都使用此种方式
URL:http://127.0.0.1:9200/索引名/_search
JSON:
{
"query":{
"match":{
"category":"关键字"
}
}
}
查找所有文档内容
向ES服务发送GET请求
URL:http://127.0.0.1:9200/索引名/_search
JSON:
{
"query":{
"match_all":{}
}
}
查找指定字段
向ES服务发送GET请求
URL:http://127.0.0.1:9200/索引名/_search
JSON:
{
"query":{
"match_all":{}
},
"_source":["字段名"]
}
分页查询
向ES服务发送GET请求
URL:http://127.0.0.1:9200/索引名/_search
JSON:
{
"query":{
"match_all":{}
},
"form":0, //页数
"size":2 //每页条数
}
查询排序
向ES服务发送GET请求
URL:http://127.0.0.1:9200/索引名/_search
JSON:
{
"query":{
"match_all":{}
},
"sort":{
"price":{
"order":"desc"
}
}
}
多条件查询-与
向ES服务发送GET请求
URL:http://127.0.0.1:9200/索引名/_search
JSON:
{
"query":{
"bool":{
"must":[{ //相当于 &&
"match":{
"category":"关键字"
}
},{
"match":{
"price":"关键字"
}
}]
}
}
}
多条件查询-或
向ES服务发送GET请求
URL:http://127.0.0.1:9200/索引名/_search
JSON:
{
"query":{
"bool":{
"should":[{ //相当于 ||
"match":{
"category":"关键字"
}
},{
"match":{
"price":"关键字"
}
}]
}
}
}
范围查询
向ES服务发送GET请求
URL:http://127.0.0.1:9200/索引名/_search
JSON:
{
"query":{
"bool":{
"should":[{ //相当于 ||
"match":{
"category":"关键字"
}
},{
"match":{
"price":"关键字"
}
}]
},
"filter":{
"range":{
"price":{
"gt":"范围" //大于
}
}
}
}
}
全文检索
向ES服务发送GET请求
URL:http://127.0.0.1:9200/索引名/_search
JSON:
{
"query":{
"match":{
"category":"关键字"
}
}
}
完全匹配
向ES服务发送GET请求
URL:http://127.0.0.1:9200/索引名/_search
JSON:
{
"query":{
"match_phrase":{
"category":"关键字"
}
}
}
高亮查询
向ES服务发送GET请求
URL:http://127.0.0.1:9200/索引名/_search
JSON:
{
"query":{
"match_phrase":{
"category":"关键字"
}
},
"highlight":{
"fileds":{
"category":{高亮字段}
}
}
}
聚合查询-带原始数据的
向ES服务发送GET请求
URL:http://127.0.0.1:9200/索引名/_search
JSON:
{
"args":{ //聚合
"price_group":{ //分组名
"terms":{ //分组
"fiels":"price" //分组的字段
}
}
}
}
聚合查询-不带原始数据的
向ES服务发送GET请求
URL:http://127.0.0.1:9200/索引名/_search
JSON:
{
"args":{ //聚合
"price_group":{ //分组名
"terms":{ //分组
"fiels":"price" //分组的字段
}
}
},
"size":0
}
映射
创建映射
注意:当创建的映射时,字段的类型为keyword时,无法模糊查询,只能精确匹配
向ES服务发送PUT请求
URL:http://127.0.0.1:9200/索引名/_mapping
JSON:
{
"properties": {
"name":{
"type": "text",
"index": true
},
"sex":{
"type": "keyword",
"index": true
},
"tel":{
"type": "keyword",
"index": false
}
}
}
查询映射
向ES服务发送GET请求
URL:http://127.0.0.1:9200/索引名/_mapping
JSON:
{
"query":{
"match":"关键字"
}
}
给映射增加数据
向ES服务发送PUT请求
URL:http://127.0.0.1:9200/索引名/_create/主键
JSON:
{
"name":"大米",
"sex":"男",
"tel":"11122223333"
}
API
整体和http部分同步,只不过是利用ES自带的API接口去实现HTTP方式的功能
创建maven工程
添加依赖
<dependencies>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.8.0</version>
</dependency>
<!-- elasticsearch 的客户端 -->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.8.0</version>
</dependency>
<!-- elasticsearch 依赖 2.x 的 log4j -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.9</version>
</dependency>
<!-- junit 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
示例代码
import java.io.IOException;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
public class HelloElasticsearch {
public static void main(String[] args) throws IOException {
// 创建客户端对象
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(new HttpHost("localhost", 9200, "http")));
// 代码逻辑
System.out.println(client);
// 关闭客户端连接
client.close();
}
}
这里以索引为例,文档与此类似,创建时需要传参,这里就不赘述
import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import java.io.IOException;
public class CreateIndex {
public static void main(String[] args) throws IOException {
// 创建客户端对象
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(new HttpHost("localhost", 9200, "http")));
// 创建索引 - 请求对象
CreateIndexRequest request = new CreateIndexRequest("user2");
// 发送请求,创建索引
CreateIndexResponse response = client.indices().create(request,
RequestOptions.DEFAULT);
boolean acknowledged = response.isAcknowledged();
System.out.println("创建的操作结果:" + acknowledged);
// 发送请求,查看索引
response = client.indices().get(request,
RequestOptions.DEFAULT);
acknowledged = response.isAcknowledged();
System.out.println("查看的操作结果:" + acknowledged);
// 发送请求,删除索引
response = client.indices().delete(request,
RequestOptions.DEFAULT);
acknowledged = response.isAcknowledged();
System.out.println("删除的操作结果:" + acknowledged);
// 发送请求,查看索引
response = client.indices().get(request,
RequestOptions.DEFAULT);
// 响应状态
acknowledged = response.isAcknowledged();
System.out.println("查看的操作结果:" + acknowledged);
// 关闭客户端连接
client.close();
}
}
部署
由多个服务器节点共同持有真个数据,提供索引搜索功能,每个集群有一个默认的名字,默认集群名为"elasticsearch",节点只能通过指定集群的名字加入集群
节点
节点就是集群中的一个服务器,参与索引和搜索功能,可以通过配置集群名称的方式让一个节点加入指定的集群,不配置就加入默认集群"elasticsearch"
集群部署-Windows
-
创建一个elasticsearch-cluster文件夹 ,复制三份elasticsearch解压后的文件结构以不同的命名到这个文件夹下
文件结构如下:
--》 elasticsearch-cluster --》 node-1001 --》 bin --》 config --》 data --》 jdk --》 lib --》 logs --》 modules --》 plugins --》 node-1002 --》 bin --》 config --》 data --》 jdk --》 lib --》 logs --》 modules --》 plugins --》 node-1003 --》 bin --》 config --》 data --》 jdk --》 lib --》 logs --》 modules --》 plugins
-
分别修改三个node下的 config/elasticsearch.yml 配置文件
#节点 的配置信息: #集群名称,节点之间要保持一致 cluster.name: my-elasticsearch #节点名称,集群内要唯一 node.name: node-1002 node.master: true node.data: true #ip 地址 network.host: localhost #http 端口 http.port: 1002 #tcp 监听端口 节点之间通信 transport.tcp.port: 9302 discovery.seed_hosts: ["localhost:9301"] discovery.zen.fd.ping_timeout: 1m discovery.zen.fd.ping_retries: 5 #集群内的可以被选为主节点的节点列表 cluster.initial_master_nodes: ["node-1", "node-2","node-3"] #跨域配置 action.destructive_requires_name: true http.cors.enabled: true http.cors.allow-origin: "*"
-
分别启动这三个节点
GET http://127.0.0.1:1001/_cluster/health 查看集群的状态
-
验证
在node1上创建的索引可以从node3中查询到,表示集群搭建完成
单节点部署-Linux
-
将下载好的ES.tar.gz解压
-
ES不允许root用户运行,需要创建新的用户
-
修改配置文件
-
/config/elasticsearch.yml中添加如下配置
cluster.name: elasticsearch node.name: node-1 network.host: 0.0.0.0 http.port: 9200 cluster.initial_master_nodes: ["node-1"]
-
/etc/security/limits.conf文件末尾追加如下配置
# 每个进程可以打开的文件数的限制 es soft nofile 65536 es hard nofile 65536
-
/etc/security/limits.d/20-nproc.conf文件末尾追加如下配置
# 每个进程可以打开的文件数的限制 es soft nofile 65536 es hard nofile 65536 # 操作系统级别对每个用户创建的进程数的限制 * hard nproc 4096 # 注: * 带表 Linux 所有用户名称
-
/etc/sysctl.conf增加如下配置
# 一个进程可以拥有的 VMA(虚拟内存区域)的数量,默认值为 65536 vm.max_map_count=655360
-
重新加载
sysctl -p
-
-
启动服务
cd /.../es/bin #启动 elasticsearch #后台启动 elasticsearch -d
-
验证,访问如下地址,返回JSON即启动成功
http://linuxIP:9200/
集群部署-Linux
大体步骤和单节点部署类似,不同的是/config/elasticsearch.yml配置文件,启动和验证和单节点部署相同
# 加入如下配置
#集群名称
cluster.name: cluster-es
#节点名称, 每个节点的名称不能重复
node.name: node-1
#ip 地址, 每个节点的地址不能重复
network.host: linux1
#是不是有资格主节点
node.master: true
node.data: true
http.port: 9200
# head 插件需要这打开这两个配置
http.cors.allow-origin: "*"
http.cors.enabled: true
http.max_content_length: 200mb
#es7.x 之后新增的配置,初始化一个新的集群时需要此配置来选举 master
cluster.initial_master_nodes: ["node-1"]
#es7.x 之后新增的配置,节点发现
discovery.seed_hosts: ["linuxIP1:9300","linuxIP2:9300","linuxIP3:9300"]
gateway.recover_after_nodes: 2
network.tcp.keep_alive: true
network.tcp.no_delay: true
transport.tcp.compress: true
#集群内同时启动的数据任务个数,默认是 2 个
cluster.routing.allocation.cluster_concurrent_rebalance: 16
#添加或删除节点及负载均衡时并发恢复的线程个数,默认 4 个
cluster.routing.allocation.node_concurrent_recoveries: 16
#初始化数据恢复时,并发恢复线程的个数,默认 4 个
cluster.routing.allocation.node_initial_primaries_recoveries: 16
进阶
故障转移
集群中有一个节点在运行时,可能出现数据丢失的情况,此时再启动一个节点,让这个节点加入集群,之前的分片后的主分片和副本分片就会被分配到不同节点,当任何一个节点出现问题时,都会有一份完整的数据,保证数据的安全
水平扩容
当集群新加入节点时,集群会将已有的分片重新分配来分散负载,数据的读写可以同时被主分片和副本分片处理,副本越多,吞吐量就越高,但是要注意,新扩展的节点如果在同一台机器上,那么就没有这个效果,因为相当于有更多的分片去共享机器的资源,而机器的资源是固定的
应对故障
假如主节点被关闭,此时集群的健康状态会到red状态,因为主节点异常了,然后集群会选举一个新的主节点,副本分片也会提升为主分片,这个过程是瞬间的,之后,集群的状态为yellow,为什么为yellow,因为设置的副本分片为2,此时只有一个副本分片了,所以不会是green,此时如果将关闭的节点再次启动,那么集群就会恢复到最开始的状态,只不过主节点不再是节点1了,而是第二个节点了
路由计算
当索引一个文档时,文档会被存放到分片中,但肯定不是随机的,因为随机的就无法而是通过一个路由算法来确定文档存放的分片:
shard = hash(routing) % number_of_primary_shards
routing默认是文档的_id,通过hash生成一个数字,然后除以分片的数量取余,这个余数就是文档将要存放的分片
还记得前面说过创建索引的时候就必须得确定主分片的数量, 并且无法修改,如果修改了,那么之前的路由就都会失效,文档就找不到了
分片控制
每个节点都有能力处理请求,每个节点都知道任何一个文档的位置,所以可以将所有的请求都发给一个节点,这个节点叫协调节点,发送请求时,建议采用轮询集群的节点
数据写的流程
这里的写包括了增和删,流程如下:
- 客户端请求协调节点
- 协调节点将请求转换到指定的节点
- 主分片对数据进行操作
- 主分片把数据发送给副本
- 副本保存后,进行反馈
- 主分片进行反馈
- 客户端获取到反馈
有几个参数会影响这个过程
- consistency
- 一致性,建议大于总分片数的一半以上,如果当前可用的分片少于这个值,那么将无法写入
- 值可以为:one(主分片正常即可写),all(所有分片正常才允许写),quorum(指定的大多数分片数)
- timeout
- 没有足够的分片时,写操作的等待时间
- 默认单位为毫秒,30s表示30秒
数据读的流程
- 客户端发送查询请求到协调节点
- 协调节点计算数据所在的分片和位置
- 请求转发给具体的节点
- 节点返回查询结果
- 将结果返回给客户端
数据更新的流程
- 客户端发送更新请求到协调节点
- 协调节点将请求转发到主分片
- 主分片完成修改后重新索引主分片的文档,如果文档无法修改(已经被其他线程持有或其他情况),会重试这个步骤,在超过一定次数后会放弃修改
- 之后将新版本文档转发到副本分片上
- 所有副本分片完成操作后都进行反馈
- 协调节点返回给客户端结果
倒排索引
是一种适用于快速的全文搜索的结构
- 正向索引,常见的key-value结构,通过key去找value,书籍的目录就是如此
- 反向索引,将所有的文件的内容切分成关键字,通过关键字可以查询到其所在的文档,搜索引擎使用较多
- 分词的优化可以提高反向索引查询的期望
- 精确匹配情况下,告诉索引我要查1,只能查到1
- 优化后,查询1,结果中可能出现one/一/One等结果
倒排索引不可变
优点
- 不需要锁,索引不变,多线程是否对同一个数据修改就可以很好避免
- 索引被读入内存中,保持不变,可减少磁盘的读写
索引的不可变也有坏处
- 如果要让新的文档可被搜索,需要重建索引
引入段的概念优化索引
为了解决索引不可变的问题,引入段的概念,每一个段也是一个倒排索引,就是一个大倒排索引下又有一堆小倒排索引,查询时向下分发,汇总查询结果,统一返回,文件新增时,新增小的倒排索引,删除时,因为是逻辑删除,查询时会匹配上,只是在返回结果中将这个文档删除了,修改时,旧版本被逻辑删除,新版本新增到新的小倒排索引中
近实时搜索
写入和打开一个新段的过程叫做刷新,默认每秒一次,可能会出现一秒内搜索不到已经创建的文档,可以使用refreshAPI或者/usersl_refresh手动刷新一次,在写操作的时候可以手动刷新,但是在查询大量的日志文件的时候,需要的是快速查询出结果,而不是实时搜索,可以通过设置refresh_interval来降低刷新频率,因为刷新会带来性能消耗
持久化变更
持久化变更,动态更新索引,在两次提交之间发生文档变化会导致数据丢失,所以Elasticsearch增加了一个translog,在每一次对Elasticsearch操作时都会记录这个事务日志,事务日志会越来越大,每次提交按照事务日志进行提交,提交之后创建一个新的事务日志,这样能够保证数据不丢失
文档分析
分析包括以下过程
- 将文本分成适合倒排索引的独立词条
- 将词条统一化成标准格式以提高可搜索性
分析器执行上面的流程,分析器包括以下三个功能
- 字符过滤器:去掉一些不必要的字符(HTML),或转化一些字符(&–>and)
- 分词器:将文本拆分成词条
- Token过滤器:改变词条(全转为小写)、删除词条(删除无意义词条)、增加词条(同义词增加)
自定义分词器
将下载的分词器放到es路径下的plugins路径下重启
文档冲突
多个线程同时修改同一个文档,只有最新的一个索引请求会生效,其他的更改将丢失,有两种控制通常确保并发时变更不会丢失
- 乐观并发控制
- 假定冲突不可能发生,如果发生,es会决定重试更新、使用最新的数据或是将情况报告给用户
- 老版本的es会使用一个版本号来控制最新的数据,新版本会报错
- 悲观并发控制
- 假定冲突发生的可能性更大,使用阻塞访问资源来防止冲突,和多线程的锁一样
es实现内部数据检查
内部数据检查需求
- 以接口为粒度
- 上游系统首次获取客户信息时调用接口
- 第二次及其之后获取同一客户信息时,在设定的有效时间内,将接口调用的最新的有效历史数据返回给上游系统
- 数据的有效时间(期望天数)可灵活配置并实时生效
- 针对不同的上游系统可配置不同的期望天数
- 不同上游系统调用的数据可共享
- 内部数据检查数据精确到天
存储结构
- 新老系统并行期间,老系统的数据需要同步到es中,需要定时任务(老系统数据到新系统表的定时任务已经有了,还差新系统的表数据到ES中)
以接口标识创建索引
如:BHZXZWSC
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qcl7B8Xh-1676472668666)(C:\Users\文杨\AppData\Roaming\Typora\typora-user-images\1669770569182.png)]
- 存储
- 每个索引存储当前接口的最大期望天数的数据量
- 查询
- 按照不同来源系统和其他条件到接口对应的索引中查询
- 删除(数据过期)
- 如果能设置文档的TTL,就可以实现定时过期
- 后期维护比较简单
- 自写定时任务删除固定日期之前的无效数据
- 维护定时任务
- 如果能设置文档的TTL,就可以实现定时过期
- 新增渠道实时生效
- 需要修改查询逻辑的代码上线
- 如果有内部数据检查的接口,仅添加配置即可
- 如果是以前没有内部数据检查的接口,还需要手动跑数(数据库到ES)
- 期望天数修改实时生效
- 如果是在最大期望天数内修改,仅修改期望天数配置,就能实时生效
- 如果超过最大期望天数,需要手动跑数到ES里
以接口标识+期望天数创建索引
如:BHZXZWSC_30
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c4UA9kDP-1676472668667)(C:\Users\文杨\AppData\Roaming\Typora\typora-user-images\1669771849757.png)]
- 存储
- 按照接口的标识和期望天数存储,每个索引仅存储对应期望天数的数据量,代码中需要存多次索引
- 查询
- es支持索引使用通配符的模糊查询,同一接口的索引名有相同的部分,可同时向多个索引发起同一查询
- 删除(数据过期)
- 如果能设置文档的TTL,就可以实现定时过期
- 后期维护比较简单
- 自写定时任务删除固定日期之前的无效数据
- 维护定时任务
- 如果能设置文档的TTL,就可以实现定时过期
- 新增渠道实时生效
- 需要修改查询逻辑的代码上线
- 添加配置并且需要手动跑数(复制或者从数据库跑数)
- 期望天数修改实时生效
- 添加配置并且手动跑数
以接口标识+渠道端+日期为索引
如:BHZXZWSC_pad_20221128
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sBbGKYRI-1676472668668)(C:\Users\文杨\AppData\Roaming\Typora\typora-user-images\1669772881920.png)]
- 存储
- 每个索引仅存储1天的数据量,代码中需要存多次索引
- 查询
- es支持索引使用通配符的模糊查询,同一接口的索引名有相同的部分,可同时向多个索引发起同一查询
- 删除(数据过期)
- 如果能设置索引的TTL,就可以实现定时过期
- 后期维护比较简单
- 自写定时任务删除固定日期之前的无效数据
- 维护定时任务
- 如果能设置索引的TTL,就可以实现定时过期
- 新增渠道实时生效
- 需要修改查询逻辑的代码上线
- 新增配置并且需要手动跑数
- 期望天数修改实时生效
- 期望天数内仅修改配置
- 期望天数之外需要手动跑数
数据查询逻辑
数据查询的逻辑比较简单,获取到期望天数,按照接口以及期望天数加上特定的逻辑去es中匹配对应的数据,结合代码结构,比较好的方式是在父类中声明查询方法,由各个子类分别重写自己的匹配逻辑
查询时聚合函数的范围查询 限制查询时间,在这个时间段内取最时间最大的一条有效数据(老系统是把期望天数内的数据都查出来,然后比对时间取最新的一条数据,这个逻辑在代码中实现,因为逻辑不会变,交给es实现)
GET localhost:9200/index-name/_search
{
"aggs" : {
"max_date": {
"max": {
"field": "dateTime"
}
}
}
}
问题
- es的查询是近实时的,当出现上游系统在短时间内多次请求同一个接口查询同一个用户的时候,会一直调用数据源接口,如避免这个问题?(在原先的老系统也有这个问题)
- 数据的存储还有什么可以优化的地方?