ES的功能真的非常强大,其背后有很多默认值,或者默认操作。这些默认操作优劣并存,优势在于我们可以迅速上手使用ES,劣势在于,其实这些默认值的背后涉及到很多底层原理,怎么做更合适,只有数据使用者知道。用ES的话来说,你比ES更懂你的数据,一些配置信息,限制信息,还是需要在了解了ES的功能之后进行人工限制。
你是否遇到:在使用了一段时间ES之后,你期望使用ES的其他功能,但因为字段类型而受限的问题?所有针对字段类型的修改都需要reindex。
在遇到一些问题后,我发现用ES很简单,但是会用ES很难。这让我下定决心一定好好了解ES,也就出现了本系列文章
前期会对ES的基本概念,常用功能的底层原理进行介绍,在对ES有了一定的了解之后,再来讨论ES到底适合应用在什么场景之下。
题主的理解若有偏差,欢迎指正👏
ES(全称 Elastic Search)是一款开源的、近实时、高性能的分布式搜索引擎, 在DBRaking热门测评中,在搜索引擎类,ES在近3年的统计数据中都霸居榜首,可见的其深受大家的喜爱。
随着ES的功能越来越强大,其和数据库的边界也越来越小,除了进行全文检索,ES也支持聚合/排序。ES底层基于Lucene开发,针对Lucene的局限性,ES提供了RESTful API风格的接口、支持分布式、可水平扩展,同时它可以被多种编程语言调用。
ES很多基础概念以及底层实现其本质是Lucene的概念。
ps:本文所有的dsl查询、结果展示均基于ES v7.7
下图这个人叫Doug Cutting,他是Hadoop语言和Lucene工具包的创始人。Doug Cutting毕业于斯坦福大学,在Xerox积累了一定的工作经验后,从1997年开始,利用业余时间开发出了Lucene。Lucene面世于1999年,并于2005年成为Apache顶级开源项目。
Lucene的特点:
Lucene的局限性:
Shay Banon是ElasticSearch的创始人。2004年,Shay Banon基于Lucene开发了Compass,在考虑Compass的第三个版本时,他意识到有必要重写Compass的大部分内容,以“创建一个可扩展的搜索解决方案”。因此,他创建了“一个从头构建的分布式解决方案”,并使用了一个公共接口,即HTTP上的JSON,它也适用于Java以外的编程语言。
2010年,Shay Banon在发布了Elasticsearch的第一个版本。
在使用ES之前,一定要先了解ES的版本历史,这里只是列出来,可以在了解了基本概念之后再看。
ES多个版本可能出现破坏性变更,例如,在6.x,ES不允许一个Index中出现多个Type。在ES的官网,每个版本都对应着一个使用文档,下面列出一些比较重大的更新版本:
在开始介绍之前想碎碎念几句~ES的功能真的非常强大,本文仅讲述了题主接触过的部分;ES背后有很多默认值,或者默认操作,用ES的话来说,你比ES更懂你的数据,一些配置信息,限制信息,还是需要在了解了ES的功能之后进行人工限制。
Index翻译过来是索引的意思。在ES里,索引有两个含义:
index
可以被认为是一个数据库,可以承载相同scheme的数据。document
保存在一个index
里,这个过程也可以称为索引。在6.x之前,index
可以被理解为关系型数据库中的【数据库】,而type
则可以被认为是【数据库中的表】,ES在8.x完全废弃了**type
**。
使用type
允许我们在一个index
里存储多种类型的数据,数据筛选时可以指定type
。type
的存在从某种程度上可以减少index
的数量,但是type
存在以下限制:
index
下的不同type
里有两个名字相同的字段,他们的类型(string, date 等等)和配置也必须相同。type
里存在的字段,在其他没有该字段的 type 中也会消耗资源。index
内的统计数据来决定的。也就是说,一个 type 中的文档会影响另一个 type 中的文档的得分。以上限制要求我们,只有同一个index
的中的 type 都有类似的映射 (mapping) 时,才勉强适用 type
。否则,使用多个type
可能比使用多个index
消耗的资源更多。
这大概也是为什么ES决定废弃type这个概念,个人感觉type的存在,就像是一个语法糖,但是并未带来太大的收益,反而增加了复杂度。
index中的单条记录称为document
(文档),可以理解为表中的一行数据(本质差别在于document
的存储方式上,它并不是行存储)。
多条document
组成了一个index
。
"hits" : {
"total" : {
"value" : 140,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "cards_info_test",
"_type" : "_doc",
"_id" : "1092",
"_score" : 1.0,
"_source" : {
"title" : "秦时明月世界黑曜卡5000元"
...
}
}
]
}
上图为ES一条文档数据,其中:
_index
: 文档所属索引名称。
_type
:文档所属类型名(此处已默认为_doc)。
_id
:Doc的主键。在写入的时候,可以指定该Doc的ID值,如果不指定,则系统自动生成一个唯一的UUID值。
_score
:顾名思义,得分,也可称之为相关性,在查询是ES会 根据一些规则计算得分,并根据得分进行倒排。除此之外,ES支持通过Function score query
在查询时自定义score的计算规则。
_source
: 文档的原始JSON数据。
一个document
会由一个或多个filed组成,filed是ES中数据索引的最小定义单位,下面仅列举部分常用的类型。
在ES中,没有数组类型,任何字段都可以变成数组。
keyword
字段。 例如,可以将string
字段映射为用于全文搜索的text
字段,并映射为用于排序或聚合的keyword
字段:
PUT my_index
{
"mappings": {
"properties": {
"city": {
"type": "text",
"fields": {
"raw": {
"type": "keyword"
}
}
}
}
}
}
text
**字段默认无法进行排序或聚合 如果您需要索引全文内容,例如电子邮件正文或产品描述,你应该使用text
字段。
keyword
字段只能精确匹配。"doc_values": false
。doc_values是为了实现排序和聚合引入的,列式存储的数据格式,指定为false可以一定程度上节约空间。
long, integer, short, byte, double, float, half_float, scaled_float...
byte
、short
、integer
和long
)而言,应该选择足以满足用例的最小类型。scaled_float
类型的实现。scaling_factor
缩放因子设置为100,对于所有的API来说,price
看起来都像是一个双精度浮点数。但是对于ES内部,他其实是一个整数long
。"price": {
"type": "scaled_float",
"scaling_factor": 100
}
scaled_float
无法满足精度要求,可以使用double
、float
、 half_float
。Type | Minimum value | Maximum value | Significant bits / digits |
---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
numberic
,numberic
********类型更擅长********range
**************类查询**,精确查询可以尝试使用keyword
。mapping
是一个定义document
结构的过程,mapping
中定义了一个文档所包含的所有filed
信息。
定义字段索引过多会导致爆炸的映射,这可能会导致内存不足错误和难以恢复的情况,mapping
提供了一些配置对filed
进行限制,下面列举几个可能会比较常见的:
index.mapping.total_fields.limit
限制mapping
中filed的最大数量,默认值是1000(filed和object内的所有字段,都会加入计数)。
index.mapping.depth.limit
限制mapping
中object的最大深度,默认值是20。
index.mapping.field_name_length.limit
限制mapping
中字段名的长度,默认是没有限制。
在索引 document时,ES的动态mapping
会将新增内容中不存在的字段,自动的加入到映射关系中。ES会自动检测新增字段的逻辑,并赋予其默认值。
截取了部分ES官方文档中的话术,ES认为一些自动化的操作会让新手上手更容易。但是同时,又提出,你肯定比ES更了解你的数据,可能刚开始使用起来觉得比较方便,但是最好还是自己明确定义映射关系。(🙄️个人认为,这些自动操作是在用户对ES没有太多了解的情况下进行的,如果刚开始依赖了这些默认的操作,例如:新增字段使用了ES赋予的默认值,如果后续有分析、排序、聚合等操作可能会有一定限制)
⚠️在ES中,删除/变更filed定义,需要进行reindex
,所以在构建mapping
结构时记得评估好字段的用途,以使用最合适的字段类型。
match
:用于执行全文查询的标准查询,包括模糊匹配和短语或接近查询。重要参数:控制Token之间的布尔关系:operator:or/and
match_phrase
:与match查询类似但用于匹配确切的短语或单词接近匹配。重要参数:Token之间的位置距离:slop 参数,默认为0
GET /_analyze
{
"text": ["这是测试"],
"analyzer": "ik_smart"
}
//Result
{
"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
}
]
}
//match+analyzer:ik_smart
//可以查询到所有describe中包含【这是测试】、【这是】、【测试】的doc
GET /my_index/_search
{
"query": {
"match": {
"describe":{
"query": "这是测试",
"analyzer": "ik_smart"
}
}
}
}
//match_phrase + analyzer:ik_smart + slop=0(默认)
//可以查询到所有describe中包含【这是】+【测试】token间隔为0的doc(说人话就是:模糊匹配【这是测试】)
GET /my_index/_search
{
"_source": "describe",
"query": {
"match_phrase": {
"describe": "这是测试"
}
}
}
//match_phrase + analyzer:ik_smart + slop=1
//可以查询到所有describe中包含【这是】+【测试】token间隔为1的doc
//例如某个doc中describe为【这是一个测试】,【这是一个测试】分词后的token分别为【这是】【一个】【测试】
//【这是】和【测试】之间间隔了1个token【一个】,所以可以被查询到;同理【这是一个我的测试】查询不到
GET /my_index/_search
{
"query": {
"match_phrase": {
"describe":{
"query": "这是测试",
"analyzer": "ik_smart",
"slop": 1
}
}
}
}
term
是进行精确查找的关键;在Lucene中,term是中索引和搜索的最小单位。一个filed会由一个或多个term
组成,term
是由filed经过Analyzer(分词)产生。Term Dictionary
即term
词典,是根据条件查找term
的基本索引。
text
字段使用术语查询。 默认情况下,ES 会在分析过程中更改文本字段的值。 这会使查找text
字段值的精确匹配变得困难。 要搜索text
字段值,强烈建议改用match
查询。
term
还是match
,都无法判断string
类型字段是否为空字符串以上两点均是因为text
字段存储的是分词结果,如果字段值为空,分词结果将不会存储term
信息,keyword
字段存储的是原始内容。
GET /my_index/_termvectors/1657216298432499712?fields=content
{
"_index" : "my_index",
"_type" : "_doc",
"_id" : "1657216298432499712",
"_version" : 2,
"found" : true,
"took" : 0,
"term_vectors" : { }
}
GET /my_index/_termvectors/1672819694014398464?fields=card_pic
{
"_index" : "my_index",
"_type" : "_doc",
"_id" : "1672819694014398464",
"_version" : 1,
"found" : true,
"took" : 0,
"term_vectors" : {
"card_pic" : {
"field_statistics" : {
"sum_doc_freq" : 183252,
"doc_count" : 183252,
"sum_ttf" : 183252
},
"terms" : {
"" : {
"term_freq" : 1,
"tokens" : [
{
"position" : 0,
"start_offset" : 0,
"end_offset" : 0
}
]
}
}
}
}
}
https://www.jianshu.com/p/1a737a3dde86
https://www.modb.pro/db/130339
https://www.cnblogs.com/qdhxhz/p/11448451.html
https://blog.csdn.net/tengxing007/article/details/100663530
https://www.elastic.co/guide/en/elasticsearch/reference/7.7/index.html
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。