Es 学习笔记 (1)
前言
什么是es?
官网地址:https://www.elastic.co/cn/
es是基于Apache Lucene的开源分布式(全文)搜索引擎,,提供简单的RESTful API来隐藏Lucene的复杂性。
es除了全文搜索引擎之外,还可以这样描述它:
- 分布式的实时文件存储,每个字段都被索引并可被搜索
- 分布式的实时分析搜索引擎
- 可以扩展到成百上千台服务器,处理PB级结构化或非结构化数据。
es数据组织类比
Relation DB | Elasticsearch |
---|---|
数据库(database) | 索引(index) |
表(tables) | types |
行(rows) | documents |
字段(columns) | fields |
应用场景
- 站内搜索:主要和 Solr 竞争,属于后起之秀
NoSQL json文档数据库:主要抢占 Mongo 的市场,它在读写性能上优于 Mongo ,同时也支持地理位置查询,还方便地理位置和文本混合查询,属于歪打正着 (对比测试参见:http://blog.quarkslab.com/mongodb-vs-elasticsearch-the-quest-of-the-holy-performances.html) - 监控:统计以及日志类时间序的数据的存储和分析以及可视化,这方面是引领者
- 国外:Wikipedia使用 ES 提供全文搜索并高亮关键字、StackOverflow结合全文搜索与地理位置查询、Github使用Elasticsearch检索1300亿行的代码
- 国内:百度(在casio、云分析、网盟、预测、文库、直达号、钱包、风控等业务上都应用了ES,单集群每天导入30TB+数据,总共每天60TB+)、新浪 (见大数据架构--log),阿里巴巴、腾讯等公司均有对ES的使用
- 使用比较广泛的平台ELK(ElasticSearch, Logstash, Kibana)
核心概念
集群
集群(Cluster): 包含一个或多个具有相同 cluster.name 的节点.
ElasticSearch 的主旨是随时可用和按需扩容。 而扩容可以通过购买性能更强大( 垂直扩容 ,或 纵向扩容 ) 或者数量更多的服务器( 水平扩容 ,或 横向扩容 )来实现。
- 集群内节点协同工作,共享数据,并共同分担工作负荷。
- 由于节点是从属集群的,集群会自我重组来均匀地分发数据.
- cluster Name是很重要的,因为每个节点只能是群集的一部分,当该节点被设置为相同的名称时,就会自动加入群集。
- 集群中通过选举产生一个mater节点,它将负责管理集群范畴的变更,例如创建或删除索引,添加节点到集群或从集群删除节点。master 节点无需参与文档层面的变更和搜索,这意味着仅有一个 master 节点并不会因流量增长而成为瓶颈。任意一个节点都可以成为 master 节点。我们例举的集群只有一个节点,因此它会扮演 master 节点的角色。
- 作为用户,我们可以访问包括 master 节点在内的集群中的任一节点。每个节点都知道各个文档的位置,并能够将我们的请求直接转发到拥有我们想要的数据的节点。无论我们访问的是哪个节点,它都会控制从拥有数据的节点收集响应的过程,并返回给客户端最终的结果。这一切都是由 Elasticsearch 透明管理的
节点(node)
一个节点是一个逻辑上独立的服务,可以存储数据,并参与集群的索引和搜索功能, 一个节点也有唯一的名字,群集通过节点名称进行管理和通信.
索引(Index)
索引与关系型数据库实例(Database)相当。索引只是一个 逻辑命名空间,它指向一个或多个分片(shards),内部用Apache Lucene实现索引中数据的读写
文档类型(Type)
相当于数据库中的table概念。每个文档在ElasticSearch中都必须设定它的类型。文档类型使得同一个索引中在存储结构不同文档时,只需要依据文档类型就可以找到对应的参数映射(Mapping)信息,方便文档的存取
6.x 之后废弃
文档(Document)
相当于数据库中的row, 是可以被索引的基本单位。例如,你可以有一个的客户文档,有一个产品文档,还有一个订单的文档。文档是以JSON格式存储的。在一个索引中,您可以存储多个的文档。请注意,虽然在一个索引中有多分文档,但这些文档的结构是一致的,并在第一次存储的时候指定, 文档属于一种 类型(type),各种各样的类型存在于一个 索引 中
5.x 以及之前的结构
6.x 之后结构
Mapping
定义一个文档以及其所包含的字段如何被存储和索引的方法
相当于数据库中的schema,用来约束字段的类型,不过 Elasticsearch 的 mapping 可以自动根据数据创建
核心简单域类型
Elasticsearch 支持如下简单域类型:
- 字符串: string
- 整数 : byte, short, integer, long
- 浮点数: float, double
- 布尔型: boolean
- 日期: date
当你索引一个包含新域的文档—之前未曾出现-- Elasticsearch 会使用 动态映射 ,通过JSON中基本数据类型,尝试猜测域类型,使用如下规则:
示例 | 类型 |
---|---|
JSON type | type |
布尔型: true 或者 false | boolean |
整数: 123 | long |
浮点数: 123.45 | double |
字符串,有效日期: 2014-09-15 | date |
字符串: foo bar | string |
这意味着如果你通过引号( "123" )索引一个数字,它会被映射为 string 类型,而不是 long 。但是,如果这个域已经映射为 long ,那么 Elasticsearch 会尝试将这个字符串转化为 long ,如果无法转化,则抛出一个异常。
分片(shard)
是 工作单元(worker unit) 底层的一员,用来分配集群中的数据,它只负责保存索引中所有数据的一小片。
分布式原理:shard = hash(routing) % number_of_primary_shards
- 分片是一个独立的Lucene实例,并且它自身也是一个完整的搜索引擎。
- 文档存储并且被索引在分片中,但是我们的程序并不会直接与它们通信。取而代之,它们直接与索引进行通信的
- 把分片想象成一个数据的容器。数据被存储在分片中,然后分片又被分配在集群的节点上。当你的集群扩展或者缩小时,elasticsearch 会自动的在节点之间迁移分配分片,以便集群保持均衡
- 分片分为 主分片(primary shard) 以及 从分片(replica shard) 两种。在你的索引中,每一个文档都属于一个主分片
- 从分片只是主分片的一个副本,它用于提供数据的冗余副本,在硬件故障时提供数据保护,同时服务于搜索和检索这种只读请求
- 索引中的主分片的数量在索引创建后就固定下来了,但是从分片的数量可以随时改变。
- 一个索引默认设置了5个主分片,每个主分片有一个从分片对应
(集群结构图)
架构图
从下往上来分析ElasticSearch 架构图
- Gateway代表ElasticSearch索引的持久化存储方式。包含索引信息,ClusterState(集群信息),mapping,索引碎片信息,以及transaction log等。
在Gateway中,ElasticSearch默认先把索引存储在内存中,然后当内存满的时候,再持久化到Gateway里。当ES集群关闭或重启的时候,它就会从Gateway里去读取索引数据。比如LocalFileSystem和HDFS、AS3等。
- DistributedLucene Directory,它是Lucene里的一些列索引文件组成的目录。它负责管理这些索引文件。包括数据的读取、写入,以及索引的添加和合并等。
- River,代表是数据源。是以插件的形式存在于ElasticSearch中。()
- Mapping,映射的意思,非常类似于静态语言中的数据类型。比如我们声明一个int类型的变量,那以后这个变量只能存储int类型的数据。
比如我们声明一个double类型的mapping字段,则只能存储double类型的数据。
Mapping不仅是告诉ElasticSearch,哪个字段是哪种类型。还能告诉ElasticSearch如何来索引数据,以及数据是否被索引到等。
- Search Moudle,搜索模块
- Index Moudle,索引模块
- Disvcovery,主要是负责集群的master节点发现。比如某个节点突然离开或进来的情况,进行一个分片重新分片等。这里有个发现机制。
发现机制默认的实现方式是单播和多播的形式,即Zen,同时也支持点对点的实现。另外一种是以插件的形式,即EC2。
- Scripting,即脚本语言。包括很多。如mvel、js、python等。
- Transport,代表ElasticSearch内部节点,代表跟集群的客户端交互。包括 Thrift、Memcached、Http等协议
- RESTful Style API,通过RESTful方式来实现API编程。
- 3rd plugins,代表第三方插件。
- Java(Netty),是开发框架。
- JMX,是监控。
写入\读取原理
es读工作流程
查询
- GET某一条数据,当你写入了某个document的时候,这个document会给你自动分配一个id doc id
- 查询的时候通过docid去进行查询, 也就是根据doc id进行hash路由到一个随机的shard节点上
- 这个时候它就作为协调节点,他会根据这个docid去查询到这个doc在哪个节点上,(因为我们知道读的话,shard和replica都可以去读)这时候就采用随机轮询的算法,让客户端在shard和replica中随机进行读取,读取完后,接受请求的协调节点对数据进行返回
搜索
- 客户端发送一个请求到一个协调节点上,因为不知道doc的id,不知道数据存在哪里,这个时候呢,就会将搜索的请求转发到所有的shard对应的primary shard或replica shard上
比如我有三个shard也就意味着我有三个replica,因为是读,所以,转发到三个节点上对应的shard或replica上就可以了
- 每个shard将自己的搜索的结果其实就是通过内容查询出来和请求内容相关的doc id(通过倒排索引)返回给协调节点
比如说我现在搜索的是java,它就会进行对比,进行判断,把带有java的这些内容的docid返回给协调节点,这时候协调节点就会收到类似于“java真好”,“java真不好”的这些doc 的id
- 由协调节点去拉去到此docid所对应的document的完整的数据拉取回来,然后进行数据的合并,排序,分页等操作,产出最终的结果,然后由协调节点返回给客户端
es的写流程
首先会对你要写的这条数进行hash,然后随机分发到一个节点,去执行写操作
通过hash路由到这个节点之后,数据首先写到一个buffer中(缓冲区),这时候,是搜索不到数据的,只有等1秒后,数据会从buffer中refresh到一个新的segmentfile中并持久化到磁盘。
注意点
- 如果buffer快满的时候,也会将里面的数据存储到segmentfile中
- 清空buffer,其实并非将segmentfile持久化到磁盘需要一秒时间,而是首先会将segmentfile写入os cache中,注:os cache(操作系统的内存),然后再将segmentfile持久化到磁盘中,写入oscache的同时,建立倒排索引,这时就可以供客户端进行访问了,这就是为什么说es是准实时的了,默认是每隔1秒refresh一次的,所以es是准实时的,因为写入的数据1秒之后才能被看到
当然我们可以通过es的restful api或者java api,手动执行一次refresh操作,就是手动将buffer中的数据刷入os cache中,让数据立马就可以被搜索到。
- translog,每写入一条数据,就会写入一条translog到os cache中去,每个五秒就会持久化一条translog日志文件到磁盘中去,这是为了防止电脑突然卡住,或者突然宕机造成的数据丢失问题(内存中的数据还没来的及持久化,就宕机了),如果出现这种情况,这时候,重启机器,就会读取translog到buffer和oscache中进行数据的恢复了,但是每次一条数据写入buffer,同时会写入一条日志到translog日志文件中去,所以这个translog日志文件是不断变大的。
- 当translog日志文件大到一定程度的时候,就会执行commit操作
整个commit的过程叫做flush操作,commit操作发生第一步,就是将buffer中现有数据refresh到os cache中去,然后将commit point这个文件持久化到磁盘中,这个文件记录了,这个时间点之前,你刷到os cache的所有的segmentfile,清空buffer 然后强行将os cache中所有的数据全都一个一个的通过segmentfile的形式,持久到磁盘上去,然后把translog文件删掉清空,再开一个空的translog文件,
translog是默认30分钟执行一次flush,一般我们不叫作commit操作,只是类似于一个提交的操作,我把它理解为commit,在es中的flush操作,就对应着commit的全过程。我们也可以通过es api,手动执行flush操作,手动将os cache中的数据fsync强刷到磁盘上去,记录一个commit point,清空translog日志文件
- translog其实也是先写入os cache的,默认每隔5秒刷一次到磁盘中去,所以默认情况下,可能有5秒的数据会仅仅停留在buffer或者translog文件的os cache中,如果此时机器挂了,会丢失5秒钟的数据。但是这样性能比较好,最多丢5秒的数据。也可以将translog设置成每次写操作必须是直接fsync到磁盘,但是性能会差很多
删除更新的原理
问题
每一次删除,都需要从集群中找到存储那个数据的节点在进行删除吗?
Es删除原理
如果是删除请求的话,提交的时候会生成一个.del文件,里面将某个doc标识为deleted状态,那么搜索的时候根据.del文件就知道这个doc被删除了,客户端搜索的时候,发现数据在.del文件中标志为删除就不会搜索出来了
Es更新原理
- 将原来的doc标识为deleted状态,然后重新写入一条数据。
问题
那么这并不是一个物理删除,那么物理删除实在什么时候呢?
- mege(合并)
buffer每次refresh一次,就会产生一个segment file,所以默认情况下是1秒钟一个segment file,segment file会越来越多,此时会定期执行merge
每次merge的时候,会将多个segment file合并成一个,同时这里会将标识为deleted的doc给物理删除掉,然后将新的segment file写入磁盘,这里会写一个commit point,标识所有新的segment file,然后打开segment file供搜索使用,同时删除旧的segment file
总结
es里的写流程,有4个底层的核心概念,refresh、flush、translog、merge 需要好好的去理解
运用
官方文档
- 权威文档
https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html - 中文指南
https://www.elastic.co/guide/cn/elasticsearch/guide/current/index.html - 官方扩展
https://www.elastic.co/guide/en/elasticsearch/client/index.html - php扩展
https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.x/index.html
gas油站加油汇总重构
- 读取mysql binlog 同步数据到es中
不能直接读取bing log,通过Canal来读取数据的
https://www.jianshu.com/p/87944efe1005
- 监听binlog event 事件,修改es数据
- mysql和es结合
http://x.x.x.x:9200/gas_prod_gas_history/_search
{"size":0,"query":{"bool":{"filter":{"bool":{"must":[{"range":{"oil_time":{"gte":"2020-2-12 00:00:00","lt":"2020-8-12 23:59:59"}}},{"terms":{"station_id":["cb23830cfe4066b4691fe75225212cb2","1ee7b6b3d7443617fe858f043bd8025b","34467af833ad5288e17171f8bb67888a","0aedd6b3f118f4dc5aba132a99145445","935262dd5e6a91856b403e81a0eaa5dc","1eca1cf9e7f0ec49d5a920ae975a02f7","f045592cdc8f927cd006473264b4a044","109509d5dc74b2dceff7fce054c730a6","90716c968d5bd7b3f6fab711828ca113","251c01653e6ccaba488d55575985fb27","0a6eebe2243fc77c83fa06075f5783da","530dcdd8bd71410285951ec6e7bbd824","dbb76a120b25ff79f3d71d5ee8711a0d","ed957f8e5f096d3f704c381eab27d2d4","987250e2a8f31929d14cd19b307851c4","09f733dc1b12688550ac835b0523fb87","7888bee53e6dc88f456040205e417296","df2af318c4f5d653876719b042549ede","db0bd2052f6026f92f2c8d5ae8189fad","f7b3d02ae64160d85351c55ffce3f30a"]}},{"terms":{"log_type":["1111","1112","1113"]}}]}}}},"aggs":{"group_by_station_id":{"terms":{"script":"doc['station_id'].values +'##'+ doc['provice_code'].values+'##'+ doc['city_code'].values","size":2147483647},"aggs":{"sum_num_count":{"sum":{"field":"oil_num"}},"sales":{"date_histogram":{"field":"oil_time","interval":"1d","format":"yyyy-MM-dd"},"aggs":{"sum_oil_num":{"sum":{"field":"oil_num"}}}}}}}}
碰到的问题
聚合之后不能分页码
whereIn 个数不能超过1024(默认)
group by之后,limit不好用
//查询硬件上报流水
$builder = self::select('pcode', 'station_id', 'oil_name', 'oil_type', 'oil_time')
->where($where);
//whereIn 条件拼装
foreach ($whereInArr as $key => $values) {
$builder = $builder->whereIn($key, $values);
}
$builder->groupBy(\DB::raw('pcode,station_id,oil_type,oil_name'))
->limit(10000);
$res = self::$es->queryBySql($builder);
//发现返回的结果为空
{
"from": 0,
"size": 0,
"query": {
"bool": {
"filter": [
{
"bool": {
"must": [
{
"bool": {
"must": [
{
"range": {
"updatetime": {
"from": "2020-09-01 01:10:00",
"to": null,
"include_lower": true,
"include_upper": true,
"boost": 1.0
}
}
},
{
"range": {
"updatetime": {
"from": null,
"to": "2020-09-01 23:59:59",
"include_lower": true,
"include_upper": true,
"boost": 1.0
}
}
}
],
"adjust_pure_negative": true,
"boost": 1.0
}
}
],
"adjust_pure_negative": true,
"boost": 1.0
}
}
],
"adjust_pure_negative": true,
"boost": 1.0
}
},
"_source": {
"includes": [
"pcode",
"station_id",
"oil_name",
"oil_type",
"oil_time"
],
"excludes": [
]
},
"stored_fields": [
"pcode",
"station_id",
"oil_name",
"oil_type",
"oil_time"
],
"aggregations": {
"pcode": { //pcode 在最外层,包住了其他条件,limit 也只对pcode生效了
"terms": {
"field": "pcode",
"size": 10000,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
},
"aggregations": {
"station_id": {
"terms": {
"field": "station_id",
"size": 10,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
},
"aggregations": {
"oil_type": {
"terms": {
"field": "oil_type",
"size": 10,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
},
"aggregations": {
"oil_name": {
"terms": {
"field": "oil_name",
"size": 10,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
}
}
}
}
}
}
}
}
}
}
Es 学习笔记 (1)的更多相关文章
- OpenGL ES学习笔记(三)——纹理
首先申明下,本文为笔者学习<OpenGL ES应用开发实践指南(Android卷)>的笔记,涉及的代码均出自原书,如有需要,请到原书指定源码地址下载. <OpenGL ES学习笔记( ...
- OpenGL ES 学习笔记 - Overview - 小旋的博客
移动端图形标准中,目前 OpenGL ES 仍然是比较通用的标准(Vulkan 则是新一代),这里新开一个系列用于记录学习 OpenGL ES 的历程,以便查阅理解. OverView OpenGL ...
- OpenGL ES学习笔记(二)——平滑着色、自适应宽高及三维图像生成
首先申明下,本文为笔者学习<OpenGL ES应用开发实践指南(Android卷)>的笔记,涉及的代码均出自原书,如有需要,请到原书指定源码地址下载. <Android学习笔记--O ...
- ES学习笔记
ES学习 1. 安装 1.1 ES 安装配置 curl -O https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5. ...
- OpenGL ES学习笔记(一)——基本用法、绘制流程与着色器编译
首先声明下,本文为笔者学习<OpenGL ES应用开发实践指南(Android卷)>的笔记,涉及的代码均出自原书,如有需要,请到原书指定源码地址下载. 在Android.iOS等移动平台上 ...
- 【ES】elasticsearch学习笔记
ES学习 1 优势 1.1 简单 1.1.1 相比Solor配置部署等非常简单 1.2 高效 1.2.1 ES使用Netty作为内部RPC框架,Solor使用Jetty 1.3 插件化 1.3.1 E ...
- Oracle学习笔记三 SQL命令
SQL简介 SQL 支持下列类别的命令: 1.数据定义语言(DDL) 2.数据操纵语言(DML) 3.事务控制语言(TCL) 4.数据控制语言(DCL)
- TEX学习笔记
整理在这里, 方便以后容易查找. 毕竟每个tex的模板有些不一样. Beamer: Latex beamer 学习总结 http://blog.sina.com.cn/s/blog_6cf921f30 ...
- Android学习笔记(二)——探究一个活动
//此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! 活动(Activity)是最容易吸引到用户的地方了,它是一种可以包含用户界面的组件,主要用于和用户进行交互.一 ...
随机推荐
- Eplan创建符号详细解说
如何创建新的符号库以及在项目里面导入这个新的符号库 这个就不详细的赘述了 网上很多教程 和我一样的萌新可以参考 https://wenku.baidu.com/view/18c16641e45c3b3 ...
- Golang 汇编asm语言基础学习
Golang 汇编asm语言基础学习 一.CPU 基础知识 cpu 内部结构 cpu 内部主要是由寄存器.控制器.运算器和时钟四个部分组成. 寄存器:用来暂时存放指令.数据等对象.它是一个更快的内存. ...
- 【PHP库】phpseclib - sftp远程文件操作
需求场景说明 对接的三方商家需要进行文件传输,并且对方提供的方式是 sftp 的服务器账号,我们需根据他们提供的目录进行下载和上传指定文件. 安装 composer require phpseclib ...
- 「POJ 3666」Making the Grade 题解(两种做法)
0前言 感谢yxy童鞋的dp及暴力做法! 1 算法标签 优先队列.dp动态规划+滚动数组优化 2 题目难度 提高/提高+ CF rating:2300 3 题面 「POJ 3666」Making th ...
- Luogu1038 神经网络 (拓扑排序)
拓扑排序,裸的,水的. 第一发:题读错,输出错,输入错,到处错 \(\longrightarrow\) 40pts (excuse me ?) 第二发:漏了输入层特判 \(\longrightarro ...
- 数据库运维之路——关于tempdb暴增实战案例
转眼间,2021年的第一个季度已经到了最后一个月了,由于疫情原因,最近一段时间一直在北京,基本上没有出差,每天上班下班的日子感觉时间过的好快,新的一年继续努力奋斗啊. 仔细回想一下,自己踏入到sql ...
- C#基础_类与对象的关系
类不占内存,对象占内存
- 【HTML】学习路径2-设置文档类型、网页编码、文件注释
第一章:设置文档类型 我们通常在html文件最前面写一行: <!DOCTYPE html> 这玩意有啥用? https://developer.mozilla.org/zh-CN/docs ...
- 「题解报告」 P3167 [CQOI2014]通配符匹配
「题解报告」 P3167 [CQOI2014]通配符匹配 思路 *和?显然无法直接匹配,但是可以发现「通配符个数不超过 \(10\) 」,那么我们可以考虑分段匹配. 我们首先把原字符串分成多个以一个通 ...
- 【设计模式】Java设计模式 - 动态代理
[设计模式]Java设计模式 - 动态代理 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 一个有梦有戏的人 @怒放吧德德 最近工作比较忙,没啥时间学习 目录 [设计模 ...