Elasticvue使用及DSL执行CURD
- 1 概述
- 2 什么是Elasticsearch DSL
- 3 基本结构
- 4 客户端工具介绍
- 4.1 索引介绍
- 4.2 创建简单索引
- 4.3 创建相对完整的索引
- 4.4 插入数据
- 4.4.1 基本插入操作
- 4.4.2 批量插入操作
- 5 常用的DSL查询类型
- 5.1 match查询
- 5.1.1 match工作原理
- 5.1.2 operator 参数
- 5.1.2.1 使用 OR 操作符
- 5.1.2.2 使用 AND 操作符
- 5.1.2.3 注意事项
- 5.2 match_phrase查询
- 5.2.1 slop参数
- 5.3 match_phrase_prefix查询
- 5.4 multi_match查询
- 6 总结
大家好,我是欧阳方超,可以我的公众号“欧阳方超”,后续内容将在公众号首发。
1 概述
Elasticsearch的DSL(Domain Specific Language)是一个功能强大的查询语言,允许用户以JSON格式构建复杂的查询。本文将介绍Elasticsearch DSL的基本概念、结构、常用查询类型及如何在实际应用中使用它。
2 什么是Elasticsearch DSL
Elasticsearch DSL是一种特定领域语言,用于与Elasticsearch进行交互。它提供了一种灵活且强大的方式来构建和执行查询,使用户能够高效地检索和操作数据。DSL查询以JSON格式书写,通常包含以下几个部分:
- 请求行:指定要查询的索引。
- 请求体:包含具体的查询逻辑。
3 基本结构
一个典型的DSL查询结构如下:
GET /index_name/_search
{"query": {"match": {"field": "value"}}
}
上面的DSL关键部分如下:
- index_name:要查询的索引名称。
- _search:搜索操作。
- query:指定查询条件,通常好汉各种查询类型。
4 客户端工具介绍
在本文进一步深入之前,先介绍一款操作Elasticsearch的客户端工具——Elasticvue,它是一个强大的开源工具,旨在为 Elasticsearch 提供图形化用户界面,帮助用户更高效地管理和查询数据。在客户端工具中操作Elasticsearch DSL会显得很方便,后续操作都将在该工具中进行。可以在Chrome 应用商店中所有该工具并进行安装。
下图是使用Elasticvue连接Elasticsearch后界面:
可以在Elasticvue的“REST”中执行DSL,具体操作为,在下面图左侧方框中写DSL,然后选择请求方式、输入请求路径,点击下方的“发送请求”,响应结果会出现右侧方框中。
4.1 索引介绍
Elasticsearch的索引类似于关系型数据库中库的概念,其结构主要包含mapping与setting两部分,settings设置索引的基础参数,包括分词器、分片、慢查询等等,mappings设置索引的字段参数,可以设置根字段类型、子级字段类型、孙级字段类型,还可以设置字段的格式等等。先介绍下如何使用DSL创建索引并插入数据,为后面的查询操作做铺垫。
4.2 创建简单索引
所谓简单索引,就是在创建时不显式指定settings信息的索引。如下创建了名为products的索引,在mappings中指定了该索引中文档将包含的字段name、price、created_at。其中name为text类型,用于全文搜索。text 类型允许进行分析(例如分词和词干提取),适合需要在大文本中进行搜索的字段。price为float类型,created_at为date类型。
PUT /products
{"mappings": {"properties": {"name": {"type": "text"},"price": {"type": "float"},"created_at": {"type": "date"}}}
}
4.3 创建相对完整的索引
为什么这里说的是创建相对完整的索引呢,因为完整的索引还包括分词器等信息,截止目前还没介绍分词器的概念。下面的DSL除了创建mappings外,在settings中还指定了分片数、副本数,均为1,这也是不指定时的默认值。
PUT /products
{"settings": {"index": {"number_of_shards": 1,"number_of_replicas": 1}},"mappings": {"properties": {"name": {"type": "text"},"price": {"type": "float"},"created_at": {"type": "date"}}}
}
下图为该段DSL在Elasticvue执行的结果:
4.4 插入数据
4.4.1 基本插入操作
在Elasticsearch中,插入数据通常使用POST请求,并指定要插入的索引和文档内容。以下是一个基本的示例:
POST /products/_doc/1
{"name": "头套","price": 19.99,"created_at": "2024-11-07T12:00:00"
}
在这个示例中:
- products 是索引名称。
- _doc 是文档类型(在Elasticsearch 7.x及以上版本中通常使用 _doc)。
- 1 是文档ID(如果不指定,Elasticsearch会自动生成一个ID)。
- 文档内容是一个JSON对象,包含产品的名称、价格和创建时间。
下图为在Elasticvue中执行的结果:
4.4.2 批量插入操作
如果需要批量插入多个文档,可以使用 _bulk API。以下是一个批量插入的示例:
POST /_bulk
{ "index": { "_index": "products", "_id": "2" } }
{ "name": "手套", "price": 29.99, "created_at": "2024-11-07T12:00:00" }
{ "index": { "_index": "products", "_id": "3" } }
{ "name": "脖套", "price": 39.99, "created_at": "2024-11-07T12:00:00" }
一个典型的批量插入请求由交替的操作元数据行和文档数据行组成。以下是结构的详细说明:
- 操作行:这一行指定要执行的操作(例如 index),并包含目标索引和文档 ID 的元数据。
- 文档行:这一行包含要索引的实际 JSON 文档。
下图为在Elasticvue中执行后的结果:
好,到这里数据准备完毕了,可以进行查询操作了。
5 常用的DSL查询类型
5.1 match查询
- match查询是用于全文检索基本查询类型,它会将输入的查询字符串分析为多个词项,并在指定字段中查找这些词项。
我们之前创建的products索引中,包含name字段,所以可以执行以下查询来查找包含“手”的文档:
{"query": {"match": {"name": "手"}}
}
下图为在Elasticvue中执行的结果:
上面的例子似乎没有体现出match查询的特点,为此我们再往products索引插入一些数据,以便体现出match查询的特点。
PUT /_bulk
{ "index": { "_index": "products", "_id": "6" } }
{ "name": "The quick brown fox jumps over the lazy dog.", "price": 29.99, "created_at": "2024-11-07T12:00:00" }
{ "index": { "_index": "products", "_id": "7" } }
{ "name": "A quick brown fox.", "price": 39.99, "created_at": "2024-11-07T12:00:00" }
5.1.1 match工作原理
前面提到,match查询会将输入的查询字符串分析为多个词项,并在指定字段中查找这些词项。这里详细解释一下。
文档6(_id=6)中name的值为The quick brown fox jumps over the lazy dog. 如果使用标准分析器进行索引(其实使用其他分词器进行分析也是一样的),该分词器的主要功能包括:将输入文本转为小写、根据空格和标点符号将文本拆分为多个词条(token),经过分析后,存储在倒排索引中的分词为:
{"tokens": [{"token": "the","start_offset": 0,"end_offset": 3,"type": "<ALPHANUM>","position": 0},{"token": "quick","start_offset": 4,"end_offset": 9,"type": "<ALPHANUM>","position": 1},{"token": "brown","start_offset": 10,"end_offset": 15,"type": "<ALPHANUM>","position": 2},{"token": "fox","start_offset": 16,"end_offset": 19,"type": "<ALPHANUM>","position": 3},{"token": "jumps","start_offset": 20,"end_offset": 25,"type": "<ALPHANUM>","position": 4},{"token": "over","start_offset": 26,"end_offset": 30,"type": "<ALPHANUM>","position": 5},{"token": "the","start_offset": 31,"end_offset": 34,"type": "<ALPHANUM>","position": 6},{"token": "lazy","start_offset": 35,"end_offset": 39,"type": "<ALPHANUM>","position": 7},{"token": "dog","start_offset": 40,"end_offset": 43,"type": "<ALPHANUM>","position": 8}]
}
下图为使用Elasticvue对这句英文进行分析的过程:
在搜索时,如果用户输入“the fox”,Elasticsearch会对这个输入内容进行分词,得到:
{"tokens": [{"token": "the","start_offset": 0,"end_offset": 3,"type": "<ALPHANUM>","position": 0},{"token": "fox","start_offset": 4,"end_offset": 7,"type": "<ALPHANUM>","position": 1}]
}
此时Elasticsearch会执行这样的逻辑,任何包含“the”或“fox”的文档都会被返回,因此文档6和7都将被返回,如下图所示:
5.1.2 operator 参数
match查询中,还可以通过设置operator参数控制多个搜索词之间的逻辑关系。通过设置此参数,可以决定文档匹配的严格程度。例如,设置为and时,只有同时包含所有指定词条的文档才会被返回。可以将其设置为一下两种值:
- OR(默认值):只要文档中包含任意一个搜索词,就会被视为匹配。这种设置增加了召回率,但可能会降低精确度,因为会返回包含部分匹配的文档。
- AND:所有指定的搜索词必须同时出现在文档中,才能被视为匹配。这种设置提高了精确度,因为只有包含所有搜索词的文档才会被返回。
5.1.2.1 使用 OR 操作符
该参数的缺省值为or,因此上图的查询中即使没有使用operator参数来控制匹配逻辑也能查询出多个文档,就是因为执行的是or逻辑。上图中的DSL查询等效于下面的DSL查询:
{"query": {"match": {"name": {"query": "The fox","operator":"or"}}}
}
在Elasticvue中执行效果如下:
在这个例子中,只要文档中包含“the”、“fox”中的任意一个,文档就被返回。
5.1.2.2 使用 AND 操作符
and操作符会确保所有关键词都必须存在于文档中。
{
“query”: {
“match”: {
“name”: {
“query”: “The fox”,
“operator”:“and”
}
}
}
}
在这个例子中,只有同时包含“the”和“fox”的文档才会被返回。
5.1.2.3 注意事项
- 使用and操作符时,可能会导致返回结果减少,因为要求更严格。
- 可以结合使用其他参数,如minimum_should_match,进一步控制匹配条件,例如,可以要求至少有75%的词项出现在文档中,下面的查询中四个词项有三个出现在文档中,符合至少75%匹配的原则,因此相应文档被返回:
{"query": {"match": {"name": {"query": "The brown fox jump","minimum_should_match": "75%"}}}
}
minimum_should_match还可以指定值为数字,表示至少有几个词项要出现在文档中,下面的查询要求至少有三个词项出现在文档中:
{"query": {"match": {"name": {"query": "The brown fox jump","minimum_should_match": 3}}}
}
5.2 match_phrase查询
与match不同,match_phrase查询要求文档中的词项按顺序出现,并且可以指定词项之间的间隔(slop),注意词。以下是match_phrase查询的特点:
- 短语匹配,要求所有词条必须按照指定的顺序紧邻出现(当不指定slop或slop值为0时)
- 会对搜索词进行分词,但分词后的词项必须按顺序出现在文档中
- 分词之间位置关系也会被考虑
如果我们想查找确切短语“精品全盔”,可以使用以下查询:
{"query": {"match_phrase": {"name": "精品全盔"}}
}
5.2.1 slop参数
slop参数运行在短语中插入其他词项,从而提供一定程度的灵活性。如果我们希望输入的短语的词项之间有一定数量的词的间隔,可以通过设置slop参数来实现。注意,slop表示词项之间运行的最大间隔数。
为了更清晰地演示slop的使用,在products索引中另准备两个文档,内容如下:
{ "index": { "_index": "products", "_id": "8" } }
{ "name": "elasticsearch is very powerful", "price": 29.99, "created_at": "2024-11-07T12:00:00" }
{ "index": { "_index": "products", "_id": "9" } }
{ "name": "elasticsearch powerful very is", "price": 39.99, "created_at": "2024-11-07T12:00:00" }
下面是一个使用slop的查询(值设置为2):
{"query": {"match_phrase": {"name": {"query":"elasticsearch powerful","slop":2}}}
}
查询结果显示,可以匹配到文档8和9,文档8中elasticsearch跟powerful之间有两个词项,未超过slop设置的最大词项个数2,因此被匹配到,文档9中elasticsearch跟powerful之间没有词项,即有零个词项,也为超过slop最大词项个数2,因为也被匹配到。
5.3 match_phrase_prefix查询
match_phrase_prefix查询用于查找以特定短语开头的文档。它非常适合实现自动补全功能,因为它允许用户输入部分短语,并返回所有以该短语开头的匹配结果。match_phrase_prefix查询的关键特性是允许最后一个词项作为前缀进行匹配。这意味着在输入的短语中,除了前面的词项必须按顺序匹配外,最后一个词项可以匹配任何以该词项为开头的词。以下是对这一特性的详细解释及示例。
以文档4、5为例,它们的name字段的值分别为“防冷冬季男士全盔”、“防冷冬季男士精品全盔”,执行以下查询:
{"query": {"match_phrase_prefix": {"name": {"query":"防冷冬季男士"}}}
}
将返回以下内容:
{"took": 2,"timed_out": false,"_shards": {"total": 1,"successful": 1,"skipped": 0,"failed": 0},"hits": {"total": {"value": 2,"relation": "eq"},"max_score": 6.6784973,"hits": [{"_index": "products","_id": "4","_score": 6.6784973,"_source": {"name": "防冷冬季男士全盔","price": 29.99,"created_at": "2024-11-07T12:00:00"}},{"_index": "products","_id": "5","_score": 5.9029303,"_source": {"name": "防冷冬季男士精品全盔","price": 39.99,"created_at": "2024-11-07T12:00:00"}}]}
}
5.4 multi_match查询
multi_match查询是对单字段match查询的扩展,允许在多个字段中同时进行搜索,这种查询类型非常灵活,可以根据需要指定不同的匹配策略,并且可以结合多个字段来提高搜索结果的相关性。
假设希望在多个字段中(除了name字段外)查询“防冷冬季男士”,可以将字段名写入fields后的中括号中,如下所示:
{"query": {"multi_match": {"query":"防冷冬季男士","fields":["name"]}}
}
6 总结
再不停下了文章就显得太长了,所以本篇到此结束,现在来总结一下。Elasticsearch DSL是一种特定领域语言,用于与Elasticsearch进行交互,使用户能够高效地检索和操作数据,同时介绍了用于执行DSL的客户端工具——Elasticvue,它相比Kibana更轻量,可以满足现阶段的使用需求。还介绍DSL插入单条及批量插入数据的操作。最后介绍了match、match_phrase、match_phrase_prefix、multi_match查询,每种都适合不同的场景,可以结合具体场景选择使用。
我是欧阳方超,把事情做好了自然就有兴趣了,如果你喜欢我的文章,欢迎点赞、转发、评论加关注。我们下次见。