elasticsearch简称es是一个基于lucene开源的近实时的搜索引擎。es是restful风格基于http协议。
数据插入后1s可以查询到
es基于luncene也有着luncene中段的概念。es的分片由很多个段(segment)组成,向es写数据是写到段上,段每隔1s刷到缓存和磁盘才能被我们读取到所以es是近实时的也就意味着不是存入了马上就可以查询到。
意味着可以动态调整集群的规模,弹性扩容
数据采集层 – kafka(数据缓存) – logstash(数据清洗) – es – kibana(可视化)
es的核心功能。搜索功能强大灵活快速检索。比如百度查询关键字,关键字自动提示都可以根据关键字打分查询出与关键字相关性高的相关文章以及链接,并且如果拼写错误(比如java – jave)也可以自动处理并检索。
filebeat、metricbeat
相当于数据库表的概念。index设计如果数据比较大应该基于时间对index进行分割每隔一段时间产生一个新索引,每天一个索引、每个月一个索引,es提供index template实现这个功能。
正排索引就是根据key找value。
比如mysql根据索引查询指定存储内容。但是比如我要模糊查询地址字段中包含”京“的我们需要address like “%京%”,这样是无法走索引的如果数据量特别大查询效率低下。
聚簇索引:key – 数据
非聚簇索引:key – id – 数据
正排索引就是根据value找key。
根据value用分词器进行分词形成分词词典,分词词典中京对应文档id为(10,20,30),再找到文档id对应的文档中分词出现的位置如(2,5,10)就表示京这个分词在分词器中存在,京对应的文档id分别为10、20和30,在每个文档出现的位置分别为2,5,10。
es的索引数据分为2部分 一部分是倒排索引库另一部分是数据。
item – id – 数据
相当于数据库的概念。
相当于数据库的数据库表。高版本(7.X)的es已经取消了这个概念使用默认类型_doc。
相当于数据库的行
一个文档是可以被索引查询的一个最基本的单元。
相当于数据库的字段,每个字段有不同的类型。只能新增字段不能修改或者删除字段。
相互于数据库的表结构指定每个字段的类型。
一般生产环境下需要禁用动态映射,使用动态映射可能出现集群元数据一直变更、造成数据类型与实际类型不一致、对于一些异常字段或者是扫描类的字段,也会频繁的修改mapping,导致业务不可控。一般要使用显示映射来创建es的映射
设置text类型以后,字段内容会被分词,在生成倒排索引以前,字符串会被分析器分成一个一个词项,text类型的字段不用于排序,很少用于聚合,不过适用于一些模糊匹配的数据。
不会分词,精确查找,keyword类型的字段只能通过精确值搜索到,常常被用来过滤、排序和聚合。
long -263 ~ 263
integer -231 ~ 231
short -215 ~ 215
byte -27 ~ 27
double 64位的双精度 IEEE754 浮点类型
float 32位的双精度 IEEE754 浮点类型
half_float 16位的双精度 IEEE754 浮点类型
scaled_float 缩放类型的浮点类型
在满足需求的情况下,优先使用范围小的字段,字段长度越小,索引和搜索的效率越高
PUT mapping_demo/_mapping{
“properties”: {
“datetime”: {
“type”: “date”,
“format”: “yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis”
}}}
true/false
integer_range、float_range、long_range
double_range、date_range、ip_range
可以先自定义声明一个范围类型,然后创建映射时应用
集群是一个或多个节点的集合,这些节点将共同拥有完整的数据,并跨节点提供联合索引、搜索和分析功能。
es的一个服务就是一个es节点。就是一个进程的概念,比如一台物理机搭建3个es服务那就是3个节点。
分片解决了单个索引大量文档的存储搜索是响应慢问题。就是将多个文档分片存储在不同的节点上。分片时要提前预估好大小,如果数据过大分片少了不能动态添加,只能倍增、倍减或者重新创建一个索引然后做数据迁移到新分片。es默认只有一个分片和一个副本分片单个分片如果超过30g会导致系统不稳定。
相当于分片的备份,es插入数据时数据落到主分片会有在其他节点的副本分片复制主分片的数据。es集群中有副本分片的概念,比如2个分片数据分别在node节点A,B上,B节点有A节点分片的备份这样保证了es的高可用比如A服务器宕机了可以用B服务器的备份分片中的数据。并且副本分片是可以被查询的减少了主分片的压力。注意相同的副本分片和主分片不可以放在一个服务器节点。
分词器是将全文本转换为一系列term的过程。
字符过滤器,可以有0个或者n个。可以过滤去掉一些没有意义的标签数字等等。比如html_strip过滤掉html标签。
分词,将一整段文本拆分成一个个的词,中文会根据语义来做分词,在一个分词器中有且自由一个tokenizer。
分词后的过滤,敏感词、停用词过滤删除。可以有0个或者n个。
character filter – tokenizer – token filter
可以通过 _analyzer API来测试分词的效果
post _analyzer {}
当索引文档字符类型为text时候,在创建索引时会对该字段进行分词。创建字段时会优先使用字段属性中analyzers上的分词器,如果没有并且设置了analysis.analyzer.default ,则使用该设置的分词器。如果上面两个都未设置,则使用默认的 standard 分词器,一个字一个词。
搜索的时候先对搜索的文本进行分词再去倒排索引库中查询。搜索时会优先使用指定 analyzer 的参数进行分词如果没有按照创建mapping时指定字段search_analyzer 属性依次按照创建索引时指定 setting 的 analysis.analyzer.default_search分词、查看创建索引时字段指定的 analyzer分词、 属性如果上面几种都未设置,则使用默认的 standard 分词器。
一般插入和搜索的分词器都用一套规则的话只在创建索引的时候配置一个分词器就可以了。
使用es如果中文使用应该先安装一个IK分词器。
ik分词器中的简单分词器,根据语义分词成简单的词语 比如武汉市长江大桥 - 武汉市 、长江大桥
ik_分词器的全量分词器,根据语义分词成全量的词语 比如武汉市长江大桥 武汉、武汉市、市长、长江、大桥、长江大桥等等。
Elasticsearch 的集群监控信息中包含了许多的统计数据,其中最为重要的一项就是集群健康 , 它在 status 字段中展示为 green 、 yellow 或者 red。
GET /_cluster/healthred
所有的主分片和副本分片都正常运行
所有数据可用,但有些副本尚未分配,比如一个主分片两个副本分片。一个分片宕机没分配出去或者一共3个节点服务器一个主分片3个副本分片。
有主分片没能正常运行。
集群的master节点会监控集群中的节点状态,如果发现有节点宕机,会立即将宕机节点的分片数据迁移到其它节点,确保数据安全,这个叫做故障转移。当集群中的节点数少于半数,将导致整个集群不可用
shard = hash(routing) % number_of_primary_shards
创建索引的时候就确定好主分片的数量,并且永远不会改变这个数量,数量的改变将导致上述公式的结果变化,最终会导致我们的数据无法被找到。
先由master协调节点找到数据写入的主分片位置然后将数据异步复制到副本节点。数据只能写入主分片。默认写入策略是异步的如果创建索引时把参数设置为index.write.wait_for_active_shards=all ,那么必须要把所有的副本写入完成才返回客户端,防止写入主分片后主分片服务器节点宕机数据丢失。
先由master协调节点找到数据所在的主分片位置,对于读请求,为了平衡负载,请求节点会为每个请求选择不同的分片,它会循环所有分片副本。es是个近实时性的nosql,写入数据后1s后才能到es主分片并且es的主分片写入副本分片也是异步的也需要时间。
先由master协调节点找到数据所在的主分片位置,更新的时候可能有多个线程同时更新es用乐观锁版本号seq_no处理并发问题。复制的时候是全量文档复制替换保证顺序问题。
在初始查询阶段会广播到索引的每一个分片,每个分片在本地执行搜索并构建一个匹配文档的优先队列(根据相关性评分排序相关性高的在前面)。
每个分片在本地执行查询请求并且创建一个长度为 from + size 的本地优先队列,也就是说,每个分片创建的结果集足够大,均可以满足全局的搜索请求,分片返回一个轻量级的结果列表到协调节点,它仅包含文档 ID 集合以及任何排序需要用到的值,例如 _score,master协调节点将这些分片级的结果合并到自己的有序优先队列里,它代表了全局排序结果集合,在做分页,至此查询过程结束。这也是大数据中的流式计算加归并排序的思想。
思想和shardingjdbc差不多。分页时候都是m+n,比如100页后10条数据,每个分片都查询0到110汇总到master协调节点后做2次聚合排序。大于一万页需要深度分页方案处理比如scroll滚动查询、search after查询。
搜索的目的是为了拿到id,返回的协调节点是个id值,然后根据id去文档中拿具体的数据。
写和读都是用相同的路由键,再写入的时候也指定路由键,路由键只能指定一个。比如一个索引有100个分片通过routingKey就可以定位到需要查询的分片有些类似于shardingjdbc的分片键可以通过分片键定位到指定分片。
别名,有点类似数据库的视图,别名一般都会和一些过滤条件相结合,可以做到即使是同一个索引上,让不同人看到不同的数据,索引和别名是多对多的关系。
POST /_aliases
{“actions”: [
{“add”: {“index”: a,“alias”:b }}
]}
要先移除再新增
我们可以创建一个带过滤器的别名,这样别人通过这个别名查询的时候,数据都是筛选过后的数据,起到一个数据权限的作用。
我们上面介绍了路由的使用,但是有一个问题,我们查询的时候都需要携带路由参数,很麻烦,我们可以将我们的路由参数写进别名中,这样查询起来会更加方便
ES是不支持索引字段类型变更的,不可变的原因是一个字段的类型进行修改之后,ES会重新建立对这个字段的索引信息,影响到ES对该字段分词方式,相关度,TF/IDF倒排索引创建等。
post reindex 将旧索引的数据拉到新索引。
将oldindex别名移除掉,在新的索引加上相同别名
如果字段类型为text类型会做分词查询,match查询的时候会对查询的词做分词处理,跟所有分词相关的内容都会被查询出来,再根据查询结果的相关性做排序展示结果。
查询的operator默认为or就是分词的所有相关性结果都可以展示,如果改为and则只能展示出所有分词相关性都满足的字段,比如查询的是长江大桥,分词为长江和大桥,如果是默认的可以查出长江大河,鹦鹉洲大桥等如果operator设置为and只能查询出武汉长江大桥等必须包含长江大桥的数据。
不进行分词。如果这个字段是keyword类型match查询的时候也是不会做分词的这个词作为一个整体存在的。
比match更严格的短句分词,分词后的词项顺序必须和文档中词项的顺序相同,并且分词后所有的词项都必须要出现在该字段中类似match中的operator设置为and不过match_phrase的特点是可以保证分词词项的顺序。
特殊的match_phrase查询,比如文档中字段的内容是武汉市光谷小学。我们用match_phrase查询搜索的词条是武汉市光,这样是查询不到的,如果用match_phrase_prefix就可以它可以用最后一个词做模糊匹配。类似mysql中like “光%” 的效果,不过这样会全表扫描这样效率比较低不推荐使用。
multi_match可以支持多个字段的全文检索。将搜索词分词后可以根据分词从不同的字段中查询并集,只要有一个匹配上就可以查询到。
默认的,使用匹配的最佳字段对应的_score(分值)排序,分词后所有字段的查询结果哪个高哪个在前面。
查询与任何字段匹配的文档。并将所有匹配字段的分值合并。分词后所有字段的查询结果评分的并集排序。
在每个匹配上的字段运行match_phrase,所有字段的查询结果评分的并集排序。
在每个匹配上的字段运行match_phrase,_prifix,所有字段的查询结果评分的并集排序。
根据自定义字符串表达式检索支持多字段联合查询,and(与)、or(或)、not(非)、exists(存在)、missing(不存在,通常用exists取非 missing效率比较低)
词项查询是精确匹配的查询不会分词。直接用查询的词与倒排索引库匹配。
比较适合于字段是keyword的查询。
可以用来查询文档中包含多个词的文档,多个词之间是or的关系。
范围查询且只能作用在一个字段上 。gt(>)、gte(>=)、lt(<)、lte(<=)、format(时间格式化,es存的是时间戳)
判断es索引某个字段是否有值。空字符串也是有值的null才是空值。
前缀查询,相当于like"武汉%",效率比较低不推荐使用。
?匹配一个任意字符。*匹配一个或多个字符。
正则查询
根据多个id查询,相当于in
fuzzy查询就是通过计算词项与文档的距离来得到结果的。
在实际搜索场景可能打错字,match查询是通过fuzziness属性实现模糊查询的fuzziness一般设置为auto,在词项查询中,使用fuzzy查询与关键字相似的文档。可以替换字符、删除字符、插入字符、转置字符.
highlight属性支持指定字段高亮展示。
must : 参与评分,必须存在相当于and
should:参与评分,结果可以匹配should下的也可以不匹配,评分和 = must评分+should评分也就是满足should评分更高
must _not:不影响评分,只是去掉不相关的文档。
filter:不参与评分,只起到过滤的作用,和must一样。
可以用positive属性评分不变,negative属性降低评分,比如2018年以后得数据相关性评分要更少可以降低评分并给一个系数negative_boost。
不会计算评分,设置一个boost常量使所有评分一样,这样查询的结果也就是随机的。
权重评分:可以在functions中设置weight为多少,会把这个属性的评分乘以设置的权重。
随机评分:可以在functions中设置random_score 评分变成随机数,业务要求每次都不一样采用这种。
脚本评分:可以使用script_score自定义脚本来设计评分
字段因子评分:自定义函数简化脚本评分。
地理位置查询。
distance:半径
lat:维度
lon:经度
根据地理位置location坐标查询半径以内的数据。
根据2个点确定一个矩形查询矩形内的数据。
根据多个坐标确定一个多边形查询多边形内的数据。