ElasticSearch
2024-10-30 22:47:56 28 举报
AI智能生成
ElasticSearch初版 2024年7月5日20:13:03又是一次大更新。 2024年9月3日18:14:28:调整思维导图的样式风格。 2024年10月30日22:47:37:SpringBoot集成部分完善
作者其他创作
大纲/内容
ES简介
什么是ES?
Elasticsearch(后称为 ES )是一个天生支持分布式的搜索、聚合分析和存储引擎
ELK
Elasticsearch
基于Json的分布式搜索和分析引擎Elastic Stack的核心
Logstash
动态数据收集管道,生态丰富
Kibana
提供数据的可视化界面
Beats
轻量级的数据采集器
特点
开源免费、分布式高性能可伸缩易扩展、、易用、跨语言
常见指标
ES支持的搜索类型
结构化搜索
非结构化搜索
文本搜索
地理位置搜索
ES擅长与不擅长
ES最擅长从海量数据中检索少量相关数据,但不擅长单次查询大量数据
ES的实时写入性
侧重海量数据的检索,实时写入实时性不是很高,默认1秒。ES的实时写入和检索性能是一个二选一的行为,生产中我们经常通过牺牲写入实时性来换取更高更快的数据检索性能
ES的事务支持性
不支持
ES的极限性能
无敌!PB级数据秒内响应
核心概念
Node节点
一个节点就是一个Elasticsearch的实例,可以理解为一个 ES 的进程
注意:
一个节点 ≠ 一台服务器
Role角色(应用角度不需要太关注这个概念)
主节点(active master)
一般指活跃的主节点,一个集群中只能有一个,主要作用是对集群的管理。
候选节点(master-eligible)
当主节点发生故障时,参与选举,也就是主节点的替代节点。
数据节点(data node)
数据节点保存包含已编入索引的文档的分片。数据节点处理数据相关操作,如 CRUD、搜索和聚合。这些操作是 I/O 密集型、内存密集型和 CPU 密集型的。监控这些资源并在它们过载时添加更多数据节点非常重要。
预处理节点(ingest node)
预处理节点有点类似于logstash的消息管道,所以也叫ingest pipeline,常用于一些数据写入之前的预处理操作。
Index索引
索引是什么?
在 ES 中,索引表述的含义等价于 MySQL 中的表
索引的组成
alias
索引别名
settings
索引设置,常见设置如分片和副本的数量等
mapping
即映射,定义了索引中包含哪些字段,以及字段的类型、长度、分词器等
Type(7.0版本后删除了这个概念)
Document文档
什么是Document?
理解为mysql里的行记录,JSON格式
Document的结构 doc struct
meta data
所有的元字段均已下划线开头,为系统字段
_index:索引名称
_id:文档 id。
_version:版本号
_seq_no:索引级别的版本号,索引中所有文档共享一个 _seq_no
_primary_term:_primary_term是一个整数,每当Primary Shard发生重新分配时,比如节点重启,Primary选举或重新分配等,_primary_term会递增1。主要作用是用来恢复数据时处理当多个文档的_seq_no 一样时的冲突,避免 Primary Shard 上的数据写入被覆盖。
source data
指业务数据,即最终写入的用户数据。
Cluster集群
单体服务的问题:
处理能力(包括吞吐量、并发能力、和算力等)有限,当业务量不断增加时,单体服务无法满足。
所有的服务依赖于同一个节点,当该节点出现故障,服务就完全不可用,风险高,可用性差
为什么是集群?
看上面
ES集群的一些概念
自动发现
核心配置
集群的健康值检查
健康状态
绿色:所有分片都可用
黄色:至少有一个副本不可用,但是所有主分片都可用,此时集群能提供完整的读写服务,但是可用性较低。
红色:至少有一个主分片不可用,数据不完整。此时集群无法提供完整的读写服务。集群不可用。
健康值检查
GET _cat/health
GET _cluster/health
Shard分片
什么是分片?
如过用一句话来概括,分片可以理解为 索引的碎片。并且所有碎片都是可以无限复制的
分片的种类
主分片(primary shard)
副本分片(replica shard)
分片的基本策略
一个索引包含一个或多个分片,在7.0之前默认五个主分片,每个主分片一个副本;在7.0之后默认一个主分片。副本可以在索引创建之后修改数量,但是主分片的数量一旦确定不可修改,只能创建索引
每个分片都是一个Lucene实例,有完整的创建索引和处理请求的能力
ES会自动在nodes上做分片均衡 shard reblance
一个doc不可能同时存在于多个主分片中,但是当每个主分片的副本数量不为一时,可以同时存在于多个副本中
主分片和其副本分片不能同时存在于同一个节点上
完全相同的副本不能同时存在于同一个节点上
分片的作用和意义
高可用性:提高分布式服务的高可用性
提高性能:提供系统服务的吞吐量和并发响应的能力
易扩展:当集群的性能不满足业务要求时,可以方便快速的扩容集群,而无需停止服务
使用
Restful API
GET
POST
PUT
DELETE
HEAD
基本操作
Search API
GET /<index_name>/_search
GET /_search
GET /_search
可选参数
size:单次查询多少条文档,默认为 10
from:起始文档偏移量。需要为非负数,默认为0
**timeout:**指定等待每个分片响应的时间段。如果在超时到期之前未收到响应,则请求失败并返回错误。默认为无超时。
Index API
索引设置
索引设置
PUT test_setting
{
"settings": {
"number_of_shards": 1, //主分片数量为 1
"number_of_replicas": 1 //每个主分片分配一个副本
}
}
{
"settings": {
"number_of_shards": 1, //主分片数量为 1
"number_of_replicas": 1 //每个主分片分配一个副本
}
}
索引修改
PUT test_setting/_settings
{
"number_of_replicas": 0
}
{
"number_of_replicas": 0
}
静态索引设置
只能在创建索引时或在关闭状态的索引上设置
重要的静态配置
index.number_of_shards:索引的主分片的个数,默认为 1,此设置只能在创建索引时设置
每个索引的分片的数量上限为 1024,这是一个安全限制,以防止意外创建索引,这些索引可能因资源分配而破坏集群的稳定性。export ES_JAVA_OPTS=“-Des.index.max_number_of_shards=128” 可以通过在属于集群的每个节点上指定系统属性来修改限制
动态索引设置
即可以使用 _setting API 在实时修改的配置
重要的动态配置
**index.number_of_replicas:**每个主分片的副本数。默认为 1,允许配置为 0。
**index.refresh_interval:**执行刷新操作的频率,默认为1s. 可以设置 -1 为禁用刷新。
**index.max_result_window:**from + size搜索此索引 的最大值。默认为 10000. 搜索请求占用堆内存和时间 from + size,这限制了内存。
创建索引
PUT <index_name>
命名规范
以小写英文字母命名索引
不要使用驼峰或者帕斯卡命名法则
如过出现多个单词的索引名称,以全小写 + 下划线分隔的方式:如test_index
删除索引
DELETE /<index_name>
判断索引是否存在
HEAD <index_name>
PS:索引的不可变性
ES 索引创建成功之后,以下属性将不可修改
索引名称
主分片数量
字段类型
Reindex
Document API
文档的操作类型
创建
创建一条 _id 为 1 的文档,并为其添加 name 和 content 两个字段
PUT goods/_create/1
{
"name":"傻妞手机",
"content":"华人牌2060款手机傻妞"
}
PUT goods/_create/1
{
"name":"傻妞手机",
"content":"华人牌2060款手机傻妞"
}
索引(创建或全量更新文档)
在 ES 中,写入操作被称为 Index,这里Index为动词,即索引数据为将数据创建在 ES 中的索引,写入数据亦可称之为“索引数据”。可以是创建,也可以是全量替换
向 goods 索引中索引一条 _id 为 1 的文档,并为其添加 name 和 content 两个字段:
PUT goods/_doc/1
{
"name":"傻妞手机",
"content":"华人牌2060款手机傻妞"
}
PUT goods/_doc/1
{
"name":"傻妞手机",
"content":"华人牌2060款手机傻妞"
}
自动生成 id
创建一个文档,并随机生成文档 id:
POST test_index/_doc
{
"test_field":"test",
"test_title":"title"
}
POST test_index/_doc
{
"test_field":"test",
"test_title":"title"
}
文档的 CRUD
Document Index API
将 JSON 文档添加到指定的数据流或索引并使其可被检索。如果目标是索引并且文档已经存在,则请求更新文档并增加其版本号。
基本语法 ★
PUT /<target>/_doc/<_id>
PUT /<target>/_create/<_id>
POST /<target>/_create/<_id>
PUT /<target>/_create/<_id>
POST /<target>/_create/<_id>
Get API
查询指定 id 的文档
GET <index>/_doc/<_id>
判断指定 id 的文档是否存在
HEAD <index>/_doc/<_id>
_source API
使用 _source API 可以打开或者关闭源数据字段,true 为打开,false 为关闭,默认为 true
GET <index>/_doc/<_id>?_source=false
Delete API
删除索引中指定 id 的文档,Document Delete API 必须指定 id
DELETE /<index>/_doc/<_id>
Update API
修改局部字段或者数据
POST /<index>/_update/<_id>
{
"doc": {
"<field_name>": "<field_value>"
}
}
{
"doc": {
"<field_name>": "<field_value>"
}
}
Multi get (mget) API
语法
支持查询同一个索引的不同 id,也可以查询不同索引的不同 id:
GET /_mget
{
"docs": [
{
"_index": "<index_name>",
"_id": "<_id>"
},
{
"_index": "<index_name>",
"_id": "<_id>"
}
]
}
GET /_mget
{
"docs": [
{
"_index": "<index_name>",
"_id": "<_id>"
},
{
"_index": "<index_name>",
"_id": "<_id>"
}
]
}
简化语法
GET <index_name>/_mget
{
"docs": [
{
"_id": "<_id>"
},
{
"_id": "<_id>"
}
]
}
{
"docs": [
{
"_id": "<_id>"
},
{
"_id": "<_id>"
}
]
}
进一步简化
GET /<index_name>/_mget
{
"ids" : ["<_id_1>", "<_id_2>"]
}
{
"ids" : ["<_id_1>", "<_id_2>"]
}
复杂语法的意义
负责的查询语法的意义在于其可编程性高,可以针对不同的文档,指定不同的查询策略
Bulk API
语法:
POST /_bulk
POST /<index>/_bulk
{"action": {"mata data"}}
{"data"}
POST /<index>/_bulk
{"action": {"mata data"}}
{"data"}
使用场景
大数据量的批量操作,比如数据从 MySQL 中一次性写入 ES,批量写入减少了对 es 的请求次数,降低了内存开销以及对线程的占用
注意和优缺点
注意
bulk api 对 json 的语法有严格的要求,除了 delete 外,每一个操作都要两个 json 串(mata data和 source field data),且每个 json 串内不能换行,非同一个 json 串必须换行,否则会报错;
bulk 操作中,任意一个操作失败,是不会影响其他的操作的,但是在返回结果里,会告诉你异常日志
优点
优点:相较于普通的Json格式的数据操作,不会产生额外的内存消耗,性能更好,常用于大数据量的批量写入
缺点
缺点:可读性差,可能会没有智能提示
DeleteByQuery
POST /<index_name>/_delete_by_query
{
"query": {
...
}
}
{
"query": {
...
}
}
UpdateByQuery
Mapping(映射)
映射 Mapping是什么?
ES 中的 mapping 有点类似与关系数据库中表结构的概念,在 MySQL 中,表结构里包含了字段名称,字段的类型还有索引信息等。在 Mapping 里也包含了一些属性,比如字段名称、类型、字段使用的分词器、是否评分、是否创建索引等属性,并且在 ES 中一个字段可以有对个类型。
如何查看索引映射
查看完整的索引 mapping
GET /<index_name>/_mappings
查看索引中指定字段的 mapping
GET /<index_name>/_mappings/field/<field_name>
自动映射:Dynamic mapping
简介:
自动映射也叫动态映射,是 ES 在索引文档写入发生时自动创建 mapping 的一种机制。ES 在创建索引之前,并不强制要求创建索引的 mapping,ES 会根据字段的值来推断字段类型,进而自动创建并指定索引类型。自动映射器会尽可能的把字段映射为宽字段类型。
Mapping 的使用禁忌
ES 没有隐式类型转换
ES 不支持类型修改
生产环境尽可能的避免使用 dynamic mapping
自动映射器的意义是什么?
官方的解释是为了照顾入门学习者,但实际上我更建议初学者尽量避免使用自动映射器,而尽可能多的显式声明 mapping,因为显式创建 mapping 是生产环境必须的,所以这是必须掌握的技能。
反而是老手,在非生产环境中,使用自动映射会比较方便。
反而是老手,在非生产环境中,使用自动映射会比较方便。
手动映射:Explicit mapping
简介:
手动映射也叫做显式映射,即:在索引文档写入之前,认为的创建索引并且指定索引中每个字段类型、分词器等参数。
创建索引的 mapping
PUT /<index_name>
{
"mappings": {
"properties": {
"field_a": {
"<parameter_name>": "<parameter_value>"
},
...
}
}
}
{
"mappings": {
"properties": {
"field_a": {
"<parameter_name>": "<parameter_value>"
},
...
}
}
}
修改 mapping 属性
PUT <index_name>/_mapping
{
"properties": {
"<field_name>": {
"type": "text",// 必须和原字段类型相同,切不许显式声明
"analyzer":"ik_max_word",// 必须和元原词器类型相同,切必须显式声明
"fielddata": false
}
}
}
{
"properties": {
"<field_name>": {
"type": "text",// 必须和原字段类型相同,切不许显式声明
"analyzer":"ik_max_word",// 必须和元原词器类型相同,切必须显式声明
"fielddata": false
}
}
}
注意:
字段类型不可修改
字段分词器不可修改
ES数据类型 field data type
概述
每个字段都有字段数据类型或字段类型。其大致分为两种
被分词的字段类型
text
match_only_text
...
不会被分词的字段类型
keyword
数值类型
...
ES 支持的数据类型
基本数据类型
Numbers:数字类型,包含很多具体的基本数据类型
binary:编码为 Base64 字符串的二进制值。
boolean:即布尔类型,接受 true 和 false。
alias:字段别名。
Keywords:包含 keyword ★、constant_keyword 和 wildcard。
Dates:日期类型,包括 data ★ 和 data_nanos,两种类型
对象关系类型(复杂类型)
object:非基本数据类型之外,默认的 json 对象为 object 类型。
flattened:单映射对象类型,其值为 json 对象。
nested ★:嵌套类型。
join:父子级关系类型。
结构化类型
Range:范围类型,比如 long_range,double_range,data_range 等
ip:ipv4 或 ipv6 地址
version:版本号
murmur3:计算和存储值的散列
聚合数据类型
aggregate_metric_double
histogram:
文本搜索字段
text ★:文本数据类型,用于全文检索。
annotated-text:
completion ★**:**
search_as_you_type:
token_count:
文档排名类型
dense_vector:记录浮点值的密集向量。
rank_feature:记录数字特征以提高查询时的命中率。
rank_features:记录数字特征以提高查询时的命中率。
空间数据类型 ★
geo_point:纬度和经度点。
geo_shape:复杂的形状,例如多边形。
point:任意笛卡尔点。
shape:任意笛卡尔几何。
其他类型
percolator:用Query DSL 编写的索引查询。
映射参数
支持的映射参数
analyzer ★
指定分析器,只有 text 类型字段支持。
coerce
是否允许强制类型转换,支持对字段段度设置或者对整个索引设置。
true: “1” => 1
false: “1” =< 1
true: “1” => 1
false: “1” =< 1
copy_to
该参数允许将多个字段的值复制到组字段中,然后可以将其作为单个字段进行查询
doc_values ★
为了提升排序和聚合效率,默认true,如果确定不需要对字段进行排序或聚合,也不需要通过脚本访问字段值,则可以禁用doc值以节省磁盘空间(不支持 text 和 annotated_text)
dynamic ★
控制是否可以动态添加新字段,支持以下四个选项:true:(默认)允许动态映射false:忽略新字段。这些字段不会被索引或搜索,但仍会出现在_source返回的命中字段中。这些字段不会添加到映射中,必须显式添加新字段。runtime:新字段作为运行时字段添加到索引中,这些字段没有索引,是_source在查询时加载的。strict:如果检测到新字段,则会抛出异常并拒绝文档。必须将新字段显式添加到映射中。
eager_global_ordinals
用于聚合的字段上,优化聚合性能。
enabled
**是否创建倒排索引,可以对字段操作,也可以对索引操作,如果不创建索引,让然可以检索并在_source元数据中展示,谨慎使用,该状态无法修改。
fielddata ★
查询时内存数据结构,在首次用当前字段聚合、排序或者在脚本中使用时,需要字段为fielddata数据结构,并且创建倒排索引保存到堆中
fields ★
给 field 创建多字段,用于不同目的(全文检索或者聚合分析排序)
format ★
用于格式化代码
ignore_above ★
超过长度将被忽略
ignore_malformed
忽略类型错误
index_options
控制将哪些信息添加到反向索引中以进行搜索和突出显示。仅用于text 字段
index_phrases
提升exact_value查询速度,但是要消耗更多磁盘空间
index_prefixes
前缀搜索:min_chars:前缀最小长度,>0,默认2(包含)max_chars:前缀最大长度,<20,默认5(包含)
index ★
是否对创建对当前字段创建倒排索引,默认 true,如果不创建索引,该字段不会通过索引被搜索到,但是仍然会在 source 元数据中展示true 新检测到的字段将添加到映射中。(默认)false 新检测到的字段将被忽略。这些字段将不会被索引,因此将无法搜索,但仍会出现在_source返回的匹配项中。这些字段不会添加到映射中,必须显式添加新字段。strict 如果检测到新字段,则会引发异常并拒绝文档。必须将新字段显式添加到映射中
meta
附加到元字段
normalizer
文档归一化器
norms ★
是否禁用评分(在filter和聚合字段上应该禁用)。
null_value ★
为 null 值设置默认值
position_increment_gap
用于数组中相邻搜索中的搜索间隙,slop 默认 100
properties ★
除了mapping还可用于object的属性设置
search_analyzer ★
设置单独的查询时分析器
similarity
为字段设置相关度算法,支持:BM25boolean注意:classic(TF-IDF)在 ES 8.x 中已不再支持!
subobjects
ES 8 新增,subobjects 设置为 false 的字段的值,其子字段的值不被扩展为对象。
store
设置字段是否仅查询
term_vector
运维参数,在运维篇会详细讲解。
Text 类型 ★★
当一个字段是要被全文搜索的,比如邮件内容、产品描述等长文本,这些字段应该使用 text 类型。设置 text 类型以后,字段内容会被分词,在生成倒排索引以前,字符串会被分析器分成一个一个词项。text 类型的字段不用于排序,很少用于聚合。
总的来说,text 用于长文本字段,可以说是 ES 体系中最重要也是最常见的数据类型。
总结:
应用的业务场景:全文检索。
Text 类型基本声明。
Text 类型会被分词。
ES 默认情况下会为 Text 类型创建倒排索引。
keyword 类型 ★
keyword使用序号映射存储它们的文档值以获得更紧凑的表示。 此映射的工作原理是根据其词典顺序为每个术语分配一个增量整数或*序数。*该字段的文档值仅存储每个文档的序数而不是原始术语,并使用单独的查找结构在序数和术语之间进行转换。
一般用于精确匹配和聚合字段,例如 ID、电子邮件地址、主机名、状态代码、邮政编码或标签。包括范围查找。和 term 查询一起使用频率是最高的。
总结:
keyword 类型字段不会被分词。
keyword 一般用于精确查找或者聚合字段
keyword 类型超过阈值长度会直接被丢弃
Date 类型 ★
在 Elasticsearch 中,时间类型是一个非常容易踩坑的数据类型
总结:
对于yyyy-MM-dd HH:mm:ss或2021-11-1T12:20:00Z,ES 的自动映射器完全无法识别,即便是事先声明日期类型,数据强行写入也会失败。
对于时间戳和yyyy-MM-dd这样的时间格式,ES 自动映射器无法识别,但是如果事先说明了日期类型是可以正常写入的。
对于标准的日期时间类型是可以正常自动识别为日期类型,并且也可以通过手工映射来实现声明字段类型。
Nested 类型 ★
自动映射模版:Dynamic Templates
介绍:
在定义字段映射的时候,往往字段不一定有具体的名称。有时希望对一类相同或者相似特征的字段定义相同的映射,此时可以考虑使用 Dynamic template。
定义映射模板
"dynamic_templates": [
{
"my_template_name": {
... match conditions ...
"mapping": { ... }
}
},
...
]
{
"my_template_name": {
... match conditions ...
"mapping": { ... }
}
},
...
]
规则判定:conditions
match_mapping_type用于匹配数据类型
match、unmatch用以匹配字段名称规则,支持通配符、正则表达式。
path_match、path_unmatch用于嵌套字段
模板变量 ☆
分词器Text Analysis
分词器入门
分词器基本概念
分词器官方称之为文本分析器,顾名思义,是对文本进行分析处理的一种手段,基本处理逻辑为按照预先制定的分词规则,把原始文档分割成若干更小粒度的词项,粒度大小取决于分词器规则。
分词发生时期
Index Time:文档写入并创建倒排索引时期,其分词逻辑取决于映射参数analyzer
Search Time:搜索发生时期,其分词仅对搜索词产生作用
分词器的组成
切词器(Tokenizer):用于定义切词(分词)逻辑
词项过滤器(Token Filter):用于对分词之后的单个词项的处理逻辑
字符过滤器(Character Filter):用于处理单个字符
文档归一化处理:Normalization
Processors
大小写统一
时态转换
停用词:如一些语气词、介词等在大多数场景下均无搜索意义
意义
增加召回率
减小匹配次数,进而提高查询性能
_analyzer API
_analyzer API可以用来查看指定分词器的分词结果。
GET _analyze
{
"text": ["What are you doing!"],
"analyzer": "english"
}
{
"text": ["What are you doing!"],
"analyzer": "english"
}
切词器:Tokenizer
tokenizer 是分词器的核心组成部分之一,其主要作用是分词,或称之为切词。主要用来对原始文本进行细粒度拆分。拆分之后的每一个部分称之为一个 Term,或称之为一个词项。
可以把切词器理解为预定义的切词规则。
官方内置了很多种切词器,默认的切词器位 standard。
可以把切词器理解为预定义的切词规则。
官方内置了很多种切词器,默认的切词器位 standard。
词项过滤器:Token Filter
简介
词项过滤器用来处理切词完成之后的词项,例如把大小写转换,删除停用词或同义词处理等。
官方同样预置了很多词项过滤器,基本可以满足日常开发的需要。当然也是支持第三方也自行开发的。
官方同样预置了很多词项过滤器,基本可以满足日常开发的需要。当然也是支持第三方也自行开发的。
案例
Lowercase 和 Uppercase
GET _analyze
{
"filter" : ["lowercase"],
"text" : "WWW ELASTIC ORG CN"
}
GET _analyze
{
"tokenizer" : "standard",
"filter" : ["uppercase"],
"text" : ["www.elastic.org.cn","www elastic org cn"]
}
{
"filter" : ["lowercase"],
"text" : "WWW ELASTIC ORG CN"
}
GET _analyze
{
"tokenizer" : "standard",
"filter" : ["uppercase"],
"text" : ["www.elastic.org.cn","www elastic org cn"]
}
停用词
GET _analyze
{
"tokenizer": "standard",
"filter": ["stop"],
"text": ["What are you doing"]
}
### 自定义 filter
DELETE test_token_filter_stop
PUT test_token_filter_stop
{
"settings": {
"analysis": {
"filter": {
"my_filter": {
"type": "stop",
"stopwords": [
"www"
],
"ignore_case": true
}
}
}
}
}
GET test_token_filter_stop/_analyze
{
"tokenizer": "standard",
"filter": ["my_filter"],
"text": ["What www WWW are you doing"]
}
{
"tokenizer": "standard",
"filter": ["stop"],
"text": ["What are you doing"]
}
### 自定义 filter
DELETE test_token_filter_stop
PUT test_token_filter_stop
{
"settings": {
"analysis": {
"filter": {
"my_filter": {
"type": "stop",
"stopwords": [
"www"
],
"ignore_case": true
}
}
}
}
}
GET test_token_filter_stop/_analyze
{
"tokenizer": "standard",
"filter": ["my_filter"],
"text": ["What www WWW are you doing"]
}
同义词
PUT test_token_filter_synonym
{
"settings": {
"analysis": {
"filter": {
"my_synonym": {
"type": "synonym",
"synonyms": [ "good, nice => excellent" ] //good, nice, excellent
}
}
}
}
}
GET test_token_filter_synonym/_analyze
{
"tokenizer": "standard",
"filter": ["my_synonym"],
"text": ["good"]
}
DELETE test_token_filter_synonym
PUT test_token_filter_synonym
{
"settings": {
"analysis": {
"filter": {
"my_synonym": {
"type": "synonym",
"synonyms_path": "analysis/synonym.txt"
}
}
}
}
}
GET test_token_filter_synonym/_analyze
{
"tokenizer": "standard",
"text": ["a"], // a b c d s; q w e r ss
"filter": ["my_synonym"]
}
{
"settings": {
"analysis": {
"filter": {
"my_synonym": {
"type": "synonym",
"synonyms": [ "good, nice => excellent" ] //good, nice, excellent
}
}
}
}
}
GET test_token_filter_synonym/_analyze
{
"tokenizer": "standard",
"filter": ["my_synonym"],
"text": ["good"]
}
DELETE test_token_filter_synonym
PUT test_token_filter_synonym
{
"settings": {
"analysis": {
"filter": {
"my_synonym": {
"type": "synonym",
"synonyms_path": "analysis/synonym.txt"
}
}
}
}
}
GET test_token_filter_synonym/_analyze
{
"tokenizer": "standard",
"text": ["a"], // a b c d s; q w e r ss
"filter": ["my_synonym"]
}
字符过滤器:Character Filter
基本概念
分词之前的预处理,过滤无用字符
基本用法
语法
PUT <index_name>
{
"settings": {
"analysis": {
"char_filter": {
"my_char_filter": {
"type": "<char_filter_type>"
}
}
}
}
}
{
"settings": {
"analysis": {
"char_filter": {
"my_char_filter": {
"type": "<char_filter_type>"
}
}
}
}
}
参数
type:使用的字符过滤器类型名称,可配置以下值
html_strip
mapping
pattern_replace
官方支持的三种 Char Filter
HTML 标签过滤器:HTML Strip Character Filter
字符过滤器会去除 HTML 标签和转义 HTML 元素,如 、&
字符映射过滤器:Mapping Character Filter
通过定义映替换为规则,把特定字符替换为指定字符
正则替换过滤器:Pattern Replace Character Filter
内置分词器
Standard ★:默认分词器,中文支持的不理想,会逐字拆分。参数值为:standard
Pattern:以正则匹配分隔符,把文本拆分成若干词项。参数值为:pattern
Simple:除了英文单词和字母,其他统统过滤掉,参数值为:simple
Whitespace ★:以空白符分隔,不会改变大小写,参数值为:whitespace
Keyword ★:可以理解为不做任何操作的分词器,会保留原有文本的所有属性,参数值为:keyword
Stop:分词规则和 Simple Analyzer 相同,但是增加了对停用词的支持。参数值为:stop
Language Analyzer:支持全球三十多种主流语言。
Fingerprint:一种特殊领域分词器,不常用
自定义分词器:Custom Analyzer
如果 ES 内置分词器无法满足需要,可以通过对切词器、词项过滤器、字符过滤器三个组件的自由组合来自定义分词器。在使用分词器时候需要注意必须满足以下要求
Tokenizer:必须包含一个并且只能指定一个切词器,即必须指定分词器的切词规则
Token Filter:可以不指定词项过滤器,也可以指定多个词项过滤器
Char Filter:可以不指定字符过滤器,也可以指定多个字符过滤器
type 参数
analyzer 和 search_analyzer
analyzer:为字段指定的分词器,仅对文本字段生效,针对的是源数据字段,也就是source data
search_analyzer:搜索时分词器,即作用于搜索词的分词器,作用对象为,用户传入的搜索词。
当 search_analyzer 未指定时,其缺省值为 analyzer,若 analyzer 未指定,search_analyzer 和 analyzer 的值都为standard
文档归一化器:Normalizers
概念
normalizer 与 analyzer 的作用类似,都是对字段进行处理,但是不同之处在于normalizer不会对字段进行分词,也就是说 normalizer 没有 tokenizer。所以 normalizer 是作用于 keyword 类型的字段的,相当于我们需要给 keyword 类型字段做一个额外的处理时,比如转换为小写时就可以用到 normalizer
注意事项
normalizer 只能用于 keyword 类型
normalizer 设置的字段不能被分词
中文分词器
ik分词器
下载
IK下载地址:https://github.com/medcl/elasticsearch-analysis-ik
安装
创建插件文件夹:cd {es-root-path}/plugins/ && mkdir ik
将插件解压缩到文件夹:{es-root-path}/plugins/ik
重新启动 ES 服务
将插件解压缩到文件夹:{es-root-path}/plugins/ik
重新启动 ES 服务
基本使用
词库文件描述
ik 提供的两种 analyzer
ik_max_word:会将文本做最细粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,中华人民,中华,华人,人民共和国,人民,人,民,共和国,共和,和,国国,国歌”,会穷尽各种可能的组合,适合 Term Query;
ik_smart:会做最粗粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,国歌”,适合 Phrase 查询。
基于本地词库扩展
基于远程词库热更新
基于 MySQL 的词库热更新
搜索:Query DSL
查询和检索
查询:有明确的搜索条件边界。比如,年龄 15~25 岁,颜色 = 红色,价格 < 3000,这里的 15、25、红色、3000 都是条件边界。即有明确的范围界定。
检索:即全文检索,无搜索条件边界,召回结果取决于相关性,其相关性计算无明确边界性条件,如同义词、谐音、别名、错别字、混淆词、网络热梗等均可成为其相关性判断依据。
上下文对象
使用 query 关键字进行检索,倾向于相关度搜索,故需要计算评分。搜索是 Elasticsearch 最关键和重要的部分。
相关度评分:_score
使用 query 关键字进行检索,倾向于相关度搜索,故需要计算评分。相关度评分为搜索结果的排序依据,默认情况下评分越高,则结果越靠前。
如果没有指定排序字段,则默认按照评分高低排序,相关度评分为搜索结果的排序依据,默认情况下评分越高,则结果越靠前。
如果没有指定排序字段,则默认按照评分高低排序,相关度评分为搜索结果的排序依据,默认情况下评分越高,则结果越靠前。
源数据:_source
数据源过滤器
Including:结果中返回哪些 field
Excluding:结果中不要返回哪些 field,不返回的field不代表不能通过该字段进行检索,因为元数据不存在不代表索引不存在
在 mapping 中定义过滤
支持通配符,但是这种方式不推荐,因为 mapping 不可变
'PUT product
{
"mappings": {
"_source": {
"includes": [
"name",
"price"
],
"excludes": [
"desc",
"tags"
]
}
}
}
{
"mappings": {
"_source": {
"includes": [
"name",
"price"
],
"excludes": [
"desc",
"tags"
]
}
}
}
在查询中过滤
禁用 _source
优点:节省存储开销
缺点:
不支持 update、update_by_query 和 reindex API。
不支持高亮。
不支持 reindex、更改 mapping 分析器和版本升级。
通过查看索引时使用的原始文档来调试查询或聚合的功能。
将来有可能自动修复索引损坏。
不支持 update、update_by_query 和 reindex API。
不支持高亮。
不支持 reindex、更改 mapping 分析器和版本升级。
通过查看索引时使用的原始文档来调试查询或聚合的功能。
将来有可能自动修复索引损坏。
总结:如果只是为了节省磁盘,可以压缩索引比禁用 _source 更好。
分页和排序
默认情况下,搜索返回前 10 个匹配命中。
分页
from:从低几个文档开始返回,需要为非负数,默认为 :0
size:定义要返回的命中数,默认值为:10
GET <index>/_search
{
"from": 0,
"size": 20
}
{
"from": 0,
"size": 20
}
注意:
from + size 必须小于等于 10000,其原因涉及深度分页问题、
max_result_window:可以解除 from + size 必须小于 10000 的限制,但是如果不清楚其原理,而盲目修改阈值,可能会造成严重后果。
track_total_hits:允许 hits.total 返回实际数值,但是会牺牲性能
排序
GET <index>/_search
{
"sort": [
{
"<sort_field>": {
"order": "desc" // or asc
}
}
]
}
{
"sort": [
{
"<sort_field>": {
"order": "desc" // or asc
}
}
]
}
Url Query
全文检索:Full Text Query ★
全文检索知识概览
字段类型:必须是可分词的字段类型
分词逻辑:不同的分词规则,对召回结果影响很大
全文检索:即 FullText Query
倒排索引:全文检索所依赖的底层数据结构
评分算法:TF-IDF、Okapi BM25
何为全文检索
全文检索是一种搜索技术,用于在大量文本数据中查找包含用户输入的关键字的文档或记录。它可以应用于许多不同的领域,如搜索引擎、电子邮件、社交媒体、知识库、文档管理系统、电子商务等垂直领域。
全文检索的核心是建立一个倒排索引(Inverted Index),即将每个词与包含这个词的文档列表进行关联。当用户输入关键词时,系统会根据这些关键词在倒排索引中查找相应的文档列表,并将匹配度高的文档排在前面返回给用户。
在全文检索中,文本数据通常被存储在数据库或文件系统中。在搜索之前,先将文本数据分词(Tokenization),将文本分解成一系列单词(词项),并将它们存储在倒排索引中。倒排索引是一种数据结构,用于存储每个单词所在的文档列表。它使得搜索引擎可以快速地找到包含用户输入的关键字的文档。
当用户输入一个或多个关键字进行搜索时,搜索引擎将查询倒排索引,找到包含这些关键字的文档,并将它们按照相关度排序后返回给用户。搜索引擎通常使用一些算法和技术来计算文档与关键字之间的相关度,例如TF-IDF(词频-逆文档频率)算法、BM25(Okapi Best Matching 25)算法等。
全文检索的核心是建立一个倒排索引(Inverted Index),即将每个词与包含这个词的文档列表进行关联。当用户输入关键词时,系统会根据这些关键词在倒排索引中查找相应的文档列表,并将匹配度高的文档排在前面返回给用户。
在全文检索中,文本数据通常被存储在数据库或文件系统中。在搜索之前,先将文本数据分词(Tokenization),将文本分解成一系列单词(词项),并将它们存储在倒排索引中。倒排索引是一种数据结构,用于存储每个单词所在的文档列表。它使得搜索引擎可以快速地找到包含用户输入的关键字的文档。
当用户输入一个或多个关键字进行搜索时,搜索引擎将查询倒排索引,找到包含这些关键字的文档,并将它们按照相关度排序后返回给用户。搜索引擎通常使用一些算法和技术来计算文档与关键字之间的相关度,例如TF-IDF(词频-逆文档频率)算法、BM25(Okapi Best Matching 25)算法等。
优缺点
全文检索有许多优点,例如:
可以非常快速地查找文本数据;
可以处理大量的文本数据;
可以处理复杂的查询,例如布尔查询、短语查询、模糊查询等;
可以根据相关度对文档进行排序,提高搜索结果的质量。
但是,全文检索也存在一些挑战和限制,例如:
分词过程可能会存在歧义,例如“香蕉奶油”可能会被分解成“香蕉”和“奶油”,也可能被分解成“香蕉奶”和“油”;
倒排索引可能会占用大量的存储空间;
搜索结果可能会受到数据质量和相关度计算算法的影响;
全文检索不适直接用于非文本数据,例如图像、音频、视频等。
可以非常快速地查找文本数据;
可以处理大量的文本数据;
可以处理复杂的查询,例如布尔查询、短语查询、模糊查询等;
可以根据相关度对文档进行排序,提高搜索结果的质量。
但是,全文检索也存在一些挑战和限制,例如:
分词过程可能会存在歧义,例如“香蕉奶油”可能会被分解成“香蕉”和“奶油”,也可能被分解成“香蕉奶”和“油”;
倒排索引可能会占用大量的存储空间;
搜索结果可能会受到数据质量和相关度计算算法的影响;
全文检索不适直接用于非文本数据,例如图像、音频、视频等。
Match
语法
GET <index>/_search
{
"query": {
"match": {
"<field_name>": "<field_value>"
}
}
}
{
"query": {
"match": {
"<field_name>": "<field_value>"
}
}
}
语义
匹配包含某个词项的文档。如果搜索词包含多个词项,那么文档只要匹配其中任意一个词项,就会被召回。
Match All
match_all:匹配所有结果的子句
GET <index>/_search
{
"query": {
"match_all": {}
}
}
GET <index>/_search
{
"query": {
"match_all": {}
}
}
Match Phrase
短语搜索概念
Match_phrase 查询是一种短语查询,它用于匹配包含指定短语的文档。与 Match 查询不同,Match_phrase 查询只匹配包含短语的文档,而不会匹配单个词条。
匹配规则
会分词:match_phrase 首先会将查询短语拆分为单个词项。例如,如果查询短语是 “elastic org cn”,则将其拆分为三个词项:。
必须全部匹配且顺序必须相同:被检索字段必须包含 match_phrase 短语中的所有词项,并且顺序必须是相同的。比如查询短语是elastic org cn,那么只有字段中的词项必须包含"elastic"、"org"和"cn"这三个短语,切顺序不能颠倒。
Slop距离:默认情况下被检索字段包含的 match_phrase 中的词项之间不能有其他词项,即 slop 默认为 0,如果人为将 slop 设置为其他数值,则多个词项将允许有 slop 规定的距离
语法
GET <index>/_search
{
"query": {
"match_phrase": {
"<field_name>": "<field_value>"
}
}
}
{
"query": {
"match_phrase": {
"<field_name>": "<field_value>"
}
}
}
Slop 参数
slop 参数用于指定允许查询短语中各个词项之间的最大间隔数。它可以用来放宽查询短语中词项的严格顺序要求,从而使查询结果能够匹配更多的文档。
精准查询:Term-Level Query
概念
官方把我们本小节所述的知识点,也就是精准查询称之为术语级查询,术语指的其实就是词项,简单来说,术语就是在全文检索中的最小粒度文本,而术语级查询,其实指的就是不可分词的查询类型。即有明确查询条件边界的查询。如:范围查询、词项查询等。
Term Query
基本逻辑
和 match query 相比,term query 不会对搜索词分词,而且会保留搜索词原有的所有属性,如大小写、标点符号等。
数据类型
通常来说,term query 和 keyword 类型一起使用,其他不分词字段亦可。
子主题
语法
GET <index>/_search
{
"query": {
"term": {
"<keyword_field_name>": "<field_value>"
}
}
}
{
"query": {
"term": {
"<keyword_field_name>": "<field_value>"
}
}
}
term 与 keyword
子主题
特殊情况
Terms Query
语法语义
Terms 和 Term 的区别就在于 Terms 是同时匹配多个词项。
GET /_search
{
"query": {
"terms": {
"<field_name>": [ "<value1>", "<value2>" ]
}
}
}
{
"query": {
"terms": {
"<field_name>": [ "<value1>", "<value2>" ]
}
}
}
布尔查询:Boolean Query
概念
bool:可以组合多个查询条件,bool 查询也是采用 more_matches_is_better 的机制,因此满足 must 和 should 子句的文档将会合并起来计算分值
bool query 多用于多条件组合查询
bool query 多用于多条件组合查询
基本语法
GET _search
{
"query": {
"bool": {
"filter": [ // 必须符合每条件
{条件一},
{条件二}
],
"must": [ // 必须符合每条件
{条件一},
{条件二}
],
"must_not": [ // 必须不满足每个条件
{条件一},
{条件二}
],
"should": [ // 可以满足其中若干条件或全部不满足
{条件一},
{条件二}
]
}
}
}
{
"query": {
"bool": {
"filter": [ // 必须符合每条件
{条件一},
{条件二}
],
"must": [ // 必须符合每条件
{条件一},
{条件二}
],
"must_not": [ // 必须不满足每个条件
{条件一},
{条件二}
],
"should": [ // 可以满足其中若干条件或全部不满足
{条件一},
{条件二}
]
}
}
}
查询子句
Must 子句
计算相关度得分
多个条件必须同时满足
多个条件必须同时满足
Filter 子句
过滤器 cache☆ 子句(查询)必须出现在匹配的文档中。但是不像 must 会计算评分, 使用 filter 查询的评分将被忽略,并且结果会被缓存。
注:
不计算相关度分数
会被缓存
注:
不计算相关度分数
会被缓存
Should 子句
可能满足 or 子句(查询)应出现在匹配的文档中。
Must_not 子句
子句中出现的每个条件都不能满足,并且不计算相关度评分
组合查询
语义关系
当多个子句同时出现时,多个子句之间的逻辑关系为 AND,即需要同时满足。如,当同时出现 must [case1, case2] 和 must_not [case3, case4] 时,其语义为:必须同时满足 case1 和 case2,且必须同时不满足 case3、case4
minimum_should_match 参数
子查询嵌套
聚合搜索(Aggregations)
基本概念
在 Elasticsearch 中,聚合查询是一种分析和统计数据的功能。聚合查询能够处理大量的数据,执行各种统计分析,如计算总数、平均值、最大值、最小值、标准差等等,并生成相应的报告。
聚合(aggs)不同于普通查询,是目前学到的第二种大的查询分类,第一种即 query,因此在代码中的第一层嵌套由 query 变为了 aggs 。
聚合(aggs)不同于普通查询,是目前学到的第二种大的查询分类,第一种即 query,因此在代码中的第一层嵌套由 query 变为了 aggs 。
使用场景
聚合查询可以用于各种场景,比如商业智能、数据挖掘、日志分析等等。
电商平台的销售分析:统计每个地区的销售额、每个用户的消费总额、每个产品的销售量等,以便更好地了解销售情况和趋势。
社交媒体的用户行为分析:统计每个用户的发布次数、转发次数、评论次数等,以便更好地了解用户行为和趋势,同时可以将数据按照地区、时间、话题等维度进行分析。
物流企业的运输分析:统计每个区域的运输量、每个车辆的运输次数、每个司机的行驶里程等,以便更好地了解运输情况和优化运输效率。
金融企业的交易分析:统计每个客户的交易总额、每个产品的销售量、每个交易员的业绩等,以便更好地了解交易情况和优化业务流程。
智能家居的设备监控分析:统计每个设备的使用次数、每个家庭的能源消耗量、每个时间段的设备使用率等,以便更好地了解用户需求和优化设备效能。
电商平台的销售分析:统计每个地区的销售额、每个用户的消费总额、每个产品的销售量等,以便更好地了解销售情况和趋势。
社交媒体的用户行为分析:统计每个用户的发布次数、转发次数、评论次数等,以便更好地了解用户行为和趋势,同时可以将数据按照地区、时间、话题等维度进行分析。
物流企业的运输分析:统计每个区域的运输量、每个车辆的运输次数、每个司机的行驶里程等,以便更好地了解运输情况和优化运输效率。
金融企业的交易分析:统计每个客户的交易总额、每个产品的销售量、每个交易员的业绩等,以便更好地了解交易情况和优化业务流程。
智能家居的设备监控分析:统计每个设备的使用次数、每个家庭的能源消耗量、每个时间段的设备使用率等,以便更好地了解用户需求和优化设备效能。
基本语法
查询条件:指定需要聚合的文档,可以使用标准的 Elasticsearch 查询语法,如 term、match、range 等等。
聚合函数:指定要执行的聚合操作,如 sum、avg、min、max、terms、date_histogram 等等。每个聚合命令都会生成一个聚合结果。
聚合嵌套:聚合命令可以嵌套,以便更细粒度地分析数据。
GET <index_name>/_search
{
"aggs": {
"<aggs_name>": { // 聚合名称需要自己定义
"<agg_type>": {
"field": "<field_name>"
}
}
}
}
aggs_name:聚合函数的名称
agg_type:聚合种类,比如是桶聚合(terms)或者是指标聚合(avg、sum、min、max等)
field_name:字段名称或者叫域名。
聚合函数:指定要执行的聚合操作,如 sum、avg、min、max、terms、date_histogram 等等。每个聚合命令都会生成一个聚合结果。
聚合嵌套:聚合命令可以嵌套,以便更细粒度地分析数据。
GET <index_name>/_search
{
"aggs": {
"<aggs_name>": { // 聚合名称需要自己定义
"<agg_type>": {
"field": "<field_name>"
}
}
}
}
aggs_name:聚合函数的名称
agg_type:聚合种类,比如是桶聚合(terms)或者是指标聚合(avg、sum、min、max等)
field_name:字段名称或者叫域名。
三种类型的聚合
桶聚合:Bucket Aggregations
概念
类比 SQL 中的 group by 的作用,主要用于统计不同类型数据的数量。
在 Elasticsearch 中,桶聚合是一种常用的聚合查询操作,它将文档分为多个“桶”,然后在每个桶上进行统计分析。
在 Elasticsearch 中,桶聚合是一种常用的聚合查询操作,它将文档分为多个“桶”,然后在每个桶上进行统计分析。
场景
指标聚合:Metrics Aggregations
概念
场景
用于统计某个指标,如最大值、最小值、平均值,可以结合桶聚合一起使用,如按照商品类型分桶,统计每个桶的平均价格。
指标函数
平均值:Avg
最大值:Max
最小值:Min
求和:Sum
详细信息:Stats
数量:Value count
最大值:Max
最小值:Min
求和:Sum
详细信息:Stats
数量:Value count
管道聚合:Pipeline Aggregations
概念
管道聚合用于对聚合的结果进行二次聚合,如要统计绑定数量最多的标签 bucket,就是要先按照标签进行分桶,再在分桶的结果上计算最大值。
场景
用于对聚合查询的二次聚合,如统计平均成绩最高的学生,即先按照学生姓名(或 id)进行桶聚合,并计算其平均成绩,然后对其平均成绩计算最大值聚合
聚合数据类型
doc values
doc values 是正排索引的基本数据结构之一,其存在是为了提升排序和聚合效率,默认true,如果确定不需要对字段进行排序或聚合,也不需要通过脚本访问字段值,则可以禁用 doc values 值以节省磁盘空间。
fielddata
查询时内存数据结构,在首次用当前字段聚合、排序或者在脚本中使用时,需要字段为 fielddata 数据结构,并且创建倒排索引保存到堆中。与 doc value 不同,当没有doc value 的字段需要聚合时,需要打开 fielddata,然后临时在内存中建立正排索引,fielddata 的构建和管理发生在 JVM Heap 中。Fielddata 默认是不启用的,因为 text 字段比较长,一般只做关键字分词和搜索,很少拿它来进行全文匹配和聚合还有排序。
嵌套聚合
分页和排序
对聚合结果排序
多字段排序
多层聚合嵌套排序
按照内层聚合排序
过滤器
Filter
Filters
全局聚合过滤
Global
Post Filter 后置过滤
对聚合结果查询:Top Hits
对聚合结果排序:Bucket Sort
常见的查询函数
histogram
date-histogram
percentile
邻接矩阵:Adjacency matrix
集成
Spring Data集成(√)
①maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
②配置文件添加连接信息
spring:
elasticsearch:
uris: http://192.168.111.4:9200
elasticsearch:
uris: http://192.168.111.4:9200
③创建映射的实体类,实体类使用@Document注解标注,更细致的看API文档,提供了非常多实用的注解(默认情况下,这个注解会在索引未创建的情况下知道创建索引,也会知道映射字段的添加,但是它不能映射原有字段的更新、删除操作。)
④创建DAO类
extends ElasticsearchRepository<实体类, ID类型>
⑤业务分层,或者直接注入DAO类即可进行简单的CRUD
进阶:
高级查询
高级的查询用QueryBuilders工具类构建
索引维护
新增Field
默认情况下,直接在实体类里添加就可以了,会自动创建,前提是你没有取消自动创建
修改、删除Field
这种情况只能重新索引
①创建新的索引
②调用_reindx API将旧数据索引到新索引
③将应用程序指向新索引,或者创建索引别名(Alias),让应用程序继续使用旧的索引名
④删除旧索引
easy-es集成(√)
永远的神,推荐学习一下,非常牛掰!各种高级功能都帮你封装好了,向前面那个索引维护,Spring Data要直接手动处理或者手动封装,这里直接帮你封装好了,你甚至可以直接改实体类,不用关注实现,它帮你维护!在这里你可以无忧无虑的当一个SQL BOY~
spark stream集成
flink集成
索引
正排索引
document_id
=>当前文档包含的所有词项
=>当前文档包含的所有词项
在数据库管理系统(DBMS)中,主键索引就是一个正排索引的例子
正排索引的优势在于可以快速地查找某个文档里包含哪些词项。同理,正排不适用于查找包含某个词项的文档有哪些。
倒排索引
词项
=>包含当前词项的doc_id的列表
=>包含当前词项的doc_id的列表
倒排索引的优势是可以快速查找包含某个词项的文档有哪些。如果用倒排来确定哪些文档中是否包含某个词项就很鸡肋。
0 条评论
下一页