中间件-ES

elasticsearch

第一章 ES
第二章 es stack:ELK



基于mysql思考:
1、单表数据量过大时如何存储
2、复杂搜索 单表千万级时模糊搜索,文档搜索、分词后搜索等mysql无法实现的功能

明显mysql搞不定,es搜索引擎,能解决如上的问题。 可以简单理解为企业级的百度搜索

一、基础知识

1、概念

ESmysqy备注
index数据库数据库
typeN/A忽略 之前对应mysql的表, 但es趋势废弃这个默认_doc
doc
属性字段
node节点数据库节点集群环境下多个节点
master节点额外管理集群范畴的变动,如索引本身的定义,集群中添加节点、删除节点
协调节点用于路由,文档读写操作都是由协调节点路由到具体节点,不会因流量增加造成主节点瓶颈
data节点默认是数据节点
主分片分表(写)用主库并不是很合适,主分片写,一个索引会先分片(分表),比如分成3个表,则这3个主分片负责写,每个主分片再备份数据叫副分片
副本分片备份表(读)es提高容错性/吞吐量的手段,主分片写完后会备份到副本分片(主从复制的过程由ES自身完成),副本越多,读效率越高
倒排索引I love you,被拆词为三行,保存在数据字典中,每个词只对应文档

在这里插入图片描述

在这里插入图片描述

2、建索引

"aliases": {
		"qd-quotation-indexs": {}
	},
	"settings": {
		"index":{
		    ## 最大查询结果 默认10000条 分页查询结果超过了就会报错
			"max_result_window": 20000
		},
		"refresh_interval": "500ms",## 准实时的时间差异,内存查询到OS cache的周期
		"number_of_shards": 4,##主分片
		"number_of_replicas": 1, ## 副本分片
		"codec": "best_compression",
		"analysis": {
			"normalizer": {
				"lowercase_normalizer": {
					"filter": ["lowercase", "asciifolding"],
					"type": "custom",
					"char_filter": []
				}
			},
			"analyzer": {
			    ## 二、ES分词流程:Character filter-->>Tokenizer-->>Token filters
				"ngram_analyzer": {
					"type": "custom",
					"tokenizer": "ngram_tokenizer",
					"filter": ["lowercase"]
				},
				"productCode_search_analyzer": {
					"type": "custom",
					"tokenizer": "standard",
					"filter": ["lowercase"]
				}
			},
			"tokenizer": {
				"ngram_tokenizer": {
					"type": "ngram",
					"min_gram": 3,
					"max_gram": 20
				}
			}
		}
	},
	"mappings": {
		"_doc": {
			"dynamic": "false",
			"_routing": {
				"required": false
			},
			"_all": {
				"enabled": false
			},
			"properties": {
				"pkid": {
					"type": "keyword"
				},
				"belongIndustry": {
					"type": "byte"
				},
				"custNickName": {
					"type": "text",
					"analyzer": "ik_max_word"
				},
				"quotationContent": {
					"type": "text",
					"analyzer": "ngram_analyzer",
					"search_analyzer": "productCode_search_analyzer"
				},
				"standardName": {
					"type": "keyword",
					"normalizer": "lowercase_normalizer"
				},
				"staffName": {
					"type": "text",
					"analyzer": "ik_max_word"
				},
				"productList": {
					"type": "nested",
					"properties": {
						"pkid": {
							"type": "keyword"
						},
					}
				}
			}
		}

3、查询语法

POST _scripts/quotation-index-page-search-template
{
    "script": {
        "lang": "mustache",
        "source": "********替换为下面的并转义分号"
    }
}



{
	"query": {
		"bool": {
			"must": [
				{"exists": {
					"field": "pkid"
				}},
				
				
				{{#accountIdsStr}},
				{"terms": {
					"accountId": [
					{{#toJson}}accountIdsStr{{/toJson}}
					]
				}}
				{{/accountIdsStr}}
		
				{{#customerName}},
				{"match": {
					"custNickName": "{{customerName}}"
				}}
				{{/customerName}}
				
				{{#customerOpenid}},
				{"term": {
					"custOpenId": "{{customerOpenid}}"
				}}
				{{/customerOpenid}}
		
			]
			
			{{#manualQuotation}},
			"must_not": [
			{
				"exists": {
					"field": "originalText"
				}
			}
			]
			{{/manualQuotation}}
		}
	}
	{{#start}},
	"from": {{start}}
	{{/start}}
	
	{{#pageSize}},
	"size": {{pageSize}}
	{{/pageSize}}
	,
	"sort": [{
		"pkid": "desc"
	}]
}

分析器组成:
Character filter–>>Tokenizer–>>Token filters

二、应用场景

1、大数据存储

2、复杂搜索

3、日志(ELK)

三、原理

写流程

在这里插入图片描述

写入成本很大,故默认不做实时写入,攒一波批量写,先写内存,默认1s刷新到os cache即操作系统缓存,此时才能被搜索到,每刷新一次生成一个segment文件,搜索时是从segment文件中获取并合并,
段合并:小文件太多了不行,故会合并
.del文件,如果是更新操作,则会记录一个del文件中,查询好后通过del文件过滤掉结果,合并段的时候也会永久删除del了的doc。

内存中的数据会待比较久,flush操作时才刷新到磁盘,如何保证数据不丢呢? 于是就出现了translog,兜底机制,防止数据丢失的,这只是记录写的日志,并不需要分词、倒排索引等处理,写入成本远远低于写到索引数据写磁盘

读流程

1、 指定id的话 则由协调节点路由
在这里插入图片描述
2、Query Then Fetch 如果是普通的search,则由协调发给每一个分片(主副选一个),再返回id给协调结果,协调节点聚合后通过id再查一遍

Query Then Fetch 的搜索类型在文档相关性打分的时候参考的是本分片的数据,这样在文档数量较少
的时候可能不够准确,DFS Query Then Fetch 增加了一个预查询的处理,询问 Term 和 Document
frequency,这个评分更准确,但是性能会变差。

四、组件对比

es vs solr

它们都是基于Lucene搜索引擎库基础之上开发,一款优秀的,高性能的企业级搜索服务器。【是因为他们都是基于分词技术构建的倒排索引的方式进行查询】

solr太老,技术栈的核心思想跟不上
es新,流行度更高,其实也说不上两者的核心差异,solr没用过

es vs mysql

es搜索功能强于mysql,数据间关系明显低于mysql
es会比mysql快吗?
mysql索引是b-tree

为什么Elasticsearch查询速度比B-tree块?

五、常见问题

  • master节点的作用

主节点负责集群范畴的工作
a、索引创建删除等
b、主节点负责ping其他节点,确定节点状态
c、决定分片在节点间的分配等

依照单一职责原则,尽量让主节点只作为主节点,而不作为数据节点

  • 主节点选举流程

个人理解,选举原则是和大部分节点网络是通的&只有一个主节点
a、和大部分节点网络是通的,即ping一遍集群全部节点,每一个节点从ping通的节点中选一个主节点出来,包括自己。 不用等全部投票,xxxx个节点投票即可(xxxx个一般配置成集群节点数过半,防止脑裂问题)
b、如果候选主节点有多个,则按相同的排序规则,如节点id排序,选第一个

  • 集群脑裂问题(多个主节点)

在这里插入图片描述

脑裂问题是分布式系统中和分区容忍性关联度非常高的一个问题,典型原因是网络问题,造成两个机房各自为政,各自为一个集群,当网络恢复后,数据如何合并会非常非常复杂,通用的方法就是主节点的过半选举原则,比如总共5个或者6个节点时,必须要有3个或者4个节点选择主节点,这样另一个机房的就选不出主节点而不能成为一个集群

脑裂

  • 数据一致性
    通过版本号乐观锁控制,
    a、同一个分片上的数据:
    同一个docid每次写时,旧数据不变,新数据版本号+1,旧的数据会放入del中(不确定,但感觉会放),当指定版本号更新时,版本号不对就报错,未指定,则会CAS操作,先找最大的版本号,更新前再判断一把是不是最大版本号。
    b、主副分片的数据一致性(可配置一致性级别)
    写的时候,是写主分片,然后同步给副本分片,可以配置副本同步的进度,可以是大部分副本写完或者不等或者必须全部写完才返回成功,一般不会全部写完,没有强一致性
    复制可能是异步的,通过版本号控制就能确保同步的是最新的数据

  • 索引优化思考和总结
    将磁盘里的东西尽量搬进内存,减少磁盘随机读取次数(同时也利用磁盘顺序读特性),结合各种奇技淫巧的压缩算法,用极其苛刻的态度使用内存。
    对于使用Elasticsearch进行索引时需要注意:
    不需要索引的字段,一定要明确定义出来,因为默认是自动建索引的
    同样的道理,对于String类型的字段,不需要analysis的也需要明确定义出来,因为默认也是会analysis的
    选择有规律的ID很重要,随机性太大的ID(比如java的UUID)不利于查询
    Bulk方式效率高于index 大概是10倍


版权声明:本文为Wen_ching_zhou原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。