[这是我参与11月更文挑战的第17天,活动详情查看:2021最后一次更文挑战]
Elasticsearch VS MySQL
MySQL是开源的关系型数据库,设计的初衷就是为了存储与查询数据间的关系,因此适合结构化数据的存储与查询。MySQL虽然也有倒排索引、全文搜索等偏向于检索的功能,但是只适合检索小量的非结构化数据。
而Elasticsearch作为典型的非关系型之一,适合非结构化文档类数据的存储、搜索与分析。在Elasticsearch中,存在大量的功能支持用户的搜索与分析,它的诞生在开源的搜索引擎luncence之上,与luncence相比有几点优势:
- 降低门槛,无需使用JAVA集成luncence;
- 简化操作,使用REST API封装了复杂的操作,无需理解底层的细节;
- 提供大量的插件,提高效率;
- 在简化搜素的同时,还支持数据分析。
索引、type、Mapping、文档与字段
索引
在Elasticsearch中,索引是文档的集合,在旧版本的设计中被类比为关系型数据库中的database,因此索引名称默认需要全小写。
还有一个type的概念,旧版本类比为关系型数据库中的table。
但是,这种数据与数据间的逻辑关系恰恰是搜索所不需要的。因此,在ES7中type就默认为_doc,ES8后会移除type的设计。而这种不同版本的迭代,恰恰说明了Elasticsearch作为一个搜索与分析的中间件与关系型数据库的不同之处。
在ES中,索引有三层含义:
- 表示 文档的集合
- 表示
从文档到集合的一个过程 - 倒排索引:Elasticsearch基于
luncence,而luncence就是使用倒排索引来进行搜索的
倒排索引源于实际应用中需要根据属性的值来查找记录。这种索引表中的每一项都包括一个属性值和具有该属性值的各记录的地址。由于不是由记录来确定属性值,而是由属性值来确定记录的位置,因而称为倒排索引(inverted index)。带有倒排索引的文件我们称为倒排索引文件,简称倒排文件(inverted file)。
倒排索引 VS 正排索引
正排索引以文档的ID为关键字,表中记录文档中每个属性的位置信息,查找时匹配表中每个文档的ID进而找到文档。
倒排索引以属性为关键字,会生成一个字段与所在文档、所在位置的字段表,通过字段检索到所需的文档。
当一段文字被倒排索引处理时,会被划分为几个term(单词或短语,由分词器决定)。而倒排索引会存储term出现的频率与位置。在查询时,通过是否出现决定是否返回,通过出现频率以及其它的系数决定_score,而_score越高则在返回结果中越靠前,相关性也就越高。
例如:
POST /_analyze?pretty
{
"analyzer": "ik_smart",
"text": "这是一个es的测试语句"
}
分词结果:
{
"tokens": [
{
"token": "这是",
"start_offset": 0,
"end_offset": 2,
"type": "CN_WORD",
"position": 0
},
{
"token": "一个",
"start_offset": 2,
"end_offset": 4,
"type": "CN_WORD",
"position": 1
},
{
"token": "es",
"start_offset": 4,
"end_offset": 6,
"type": "ENGLISH",
"position": 2
},
{
"token": "的",
"start_offset": 6,
"end_offset": 7,
"type": "CN_CHAR",
"position": 3
},
{
"token": "测试",
"start_offset": 7,
"end_offset": 9,
"type": "CN_WORD",
"position": 4
},
{
"token": "语句",
"start_offset": 9,
"end_offset": 11,
"type": "CN_WORD",
"position": 5
}
]
}
分词图解:
Mapping
在早期的ES中,设计了_type作为一个类似与关系数据库的概念,也存在着映射(Mapping)表示数据的转换关系,可以简单的类比为表结构。但是,关系型数据库的设计毕竟不适合搜索,所以在最近的版本里已经决定在ES8就去除_type。
而Mapping却依旧永垂不朽,它决定了数据的转换关系,决定了是否动态增加数据亦或者是否在运行时修改字段。它还在扩展自己的概念,作为索引与文档沟通的桥梁。
文档
文档是字段的集合;而索引内的文档无需具有相同的格式,所以索引无法简单的类比为关系型数据库中的表。
如下所示,就是一个通过REST-API查询后返回的文档
在上图中,除了_source的子字段,其它字段(包括_source)均为元数据。含义如下:
- _index:索引
_type:索引的类型,ES7中默认为_doc,ES8移除- _id:主键,PUT数据时可添加;不添加则是一个唯一的UUID
- _version:用于数据的版本控制,这里之后再详细分析
- _seq_no:严格递增的序号,保证文档写入Lucene的顺序也是递增的
- _primary_term:整数,当主分片重新分配时,加1
- _routing:文档路由到其它分片时的重要参数之一
- found:表示是否查询到数据,如果_source存在则为true
- _source:原始JSON数据
字段
每个字段类型可以分为数据类型或元数据字段类型
数据类型是Elasticsearch解析原始JSON数据时,为字段设置的类型,定义了数据有什么元数据字段类型则是用于描述文档的信息,定义了数据是什么
数据类型(Field data types)
数据类型定义了字段包含的数据类型(例如字符串或布尔值等)及其预期用途。例如,我们可以将字符串索引到text和keyword 字段。然而,text字段值被分析用于全文搜索,而keyword字符串则保持原样用于过滤和排序。
- 常见类型
- binary 编码为 Base64 字符串的二进制值
- boolean true和false
- keywords 关键字族,其中包括keyword,constant_keyword,和wildcard
- Numerers 数字类型,例如long和double,用于表示金额
- Date 日期类型,包括 date 以及 date_nanos(精确到纳秒)
- 对象及对象关系类型
- object JSON 对象
- flattened 整个 JSON 对象作为单个字段值
- nested JSON 对象,保留其子字段之间的关系
- join 为同一索引中的文档定义父/子关系
- 结构化数据类型
- Range 范围类型,例如long_range,double_range, date_range,和ip_range
- ip IPv4 和 IPv6
- version 版本,支持版本控制
- murmur3 计算并存储值的哈希值
- 聚合数据类型
- aggregate_metric_double 预聚合的指标值
- histogram 直方图形式的预聚合数值
- 文本搜索类型
- text 文本族,包括text和match_only_text。经过分析的非结构化文本。
- annotated-text 包含特殊标记的文本。用于识别命名实体。
- completion 用于自动完成建议
- search_as_you_type 按类型搜索,会针对类型生成相应子字段,辅助搜索
- text-like type 用于按您类型完成。
- token_count 文本中搜索词命中的计数
- 文档排序类型
- dense_vector 记录浮点值的密集向量
- sparse_vector 记录浮点值的稀疏向量
- rank_feature 记录数字特征以在查询时提高命中率
- rank_features 记录数字特征以在查询时提高命中率
- 空间数据类型
- geo_point 纬度和经度点
- geo_shape 复杂的形状,例如多边形
- point 任意笛卡尔点
- shape 任意笛卡尔几何
- 其它类型
- percolator 用
Query DSL编写的索引查询
- 数组
在 Elasticsearch 中,数组不需要专用的字段数据类型。默认情况下,任何字段都可以包含零个或多个值,但是,数组中的所有值必须具有相同的字段类型。
- 多字段
为不同的目的以不同的方式索引相同的字段通常很有用。例如,一个string字段可以被映射为一个text用于全文搜索的keyword字段,以及一个用于排序或聚合的字段。这就是多字段的目的。大多数字段类型通过fields参数支持多字段。
元数据字段类型(Metadata fields)
每个文档都有与其关联的元数据,在创建映射类型时可以自定义其中一些元数据字段的行为。
元数据字段如下:
- 身份(identity)
- _index 文档所属的索引
- _type 文档的映射类型
- _id 文档的 ID
- 文档源
- _source 表示文档正文的原始 JSON。
- _size 由mapper-size插件提供 _source的字段大小(以字节为单位)
- 文档计数
- _doc_count 当文档表示预聚合数据时,用于存储文档计数的自定义字段
- 索引
- _field_names 文档中包含非空值的所有字段。
- _ignored 设置ignore_malformed=true后,当索引格式错误的字段时将忽略,并归纳到这个字段中
- 路由
- _routing 将文档路由到特定分片的自定义路由值
- 其它
- _meta 用于自定义元数据
- _tier 在跨多个索引执行查询时,有时需要将保存在给定数据层(
data_hot、data_warm、data_cold或data_frozen)节点上的索引作为目标,该字段用于设置跨索引查询的首选项