由 Evgeni Tcherkasski摄 于 Unsplash
查询elasticsearch可能会非常混乱,尤其是在您刚开始使用引擎时。 在本文中,我想为您提供一个快速入门并简化此主题。
我们的查询将发送到请求正文中的elasticsearch “ _search ” API。 通常,我们将使用弹性搜索客户端sdk之一 ,具体取决于我们要使用的语言。
在深入探讨之前,我想谈谈有关Elasticsearch索引编制和映射过程的几点。
索引过程
我们有两个文件:
Doc_1-“夏天,棕色的狐狸跳过了懒狗”
Doc_2-“敏捷的棕色狐狸跳过了懒狗”
这两个文档都由elasticsearch索引。 索引过程的结果是一个反向索引 :
文本中的每个标记都映射到相应的文档。
在编制索引的过程中,将转换文本:
- 字符过滤器 -一个或多个字符过滤器,用于清理文本,去除不需要的字符,例如HTML标签
- 标记生成器 -单标记生成器,打破了串入简单的话(令牌)
- 令牌过滤器 -零个或多个令牌过滤器,它们执行诸如小写令牌过滤器,停用词令牌过滤器,同义词过滤器等任务。
- 分析器 —字符过滤器+令牌生成器+令牌过滤器
所有这三个元素都定义了一个分析器 。 每个索引都有一个附加的分析器 。 elasticsearch具有内置的分析器,您还可以构建自己的自定义分析器并将其附加到索引。
映射
通过elasticsearch 文档 :
映射是定义文档及其包含的字段的存储和索引方式的过程。 例如,使用映射定义:
创建新索引时,有三个选项:
- 自己定义每个字段的映射
- 使用动态映射,并让elasticsearch“猜测”映射
- 两者都使用-定义重要字段,然后让elasticsearch引擎处理其余字段。
字段和映射类型在使用之前不需要定义。 通过动态映射,仅通过索引文档即可自动添加新的字段名称。 新字段既可以添加到顶级映射类型,也可以添加到内部和字段。 elasticsearch 文档
动态映射规则:
字符串字段
文本字段可以映射为:
-
Full-text
-
Keyword
-如果可能需要对结构化内容(例如电子邮件地址,主机名,状态代码或标签)建立索引,则应使用关键字字段。 该字符串被视为单个单元,并且整个字符串都已编制索引。 没有部分比赛的选择
elasticsearch动态映射是同时映射两种类型的文本字段,因此您可以通过任何方式(精确短语或部分短语)进行搜索:
{
"name" : {
"type" : "text" ,
"fields" : {
"keyword" : {
"type" : "keyword" ,
"ignore_above" : 256
}
}
}
}
日期字段
JSON没有日期数据类型,因此Elasticsearch中的日期可以是:
1. 包含格式化日期的 字符串 ,例如“ 2015-01-01”或“ 2015/01/01 12:10:30”。
2. 一个长整数, 表示从纪元以来的毫秒 数 。
3. 整数, 表示从秒开始的秒数。 官方文件
在内部,日期会转换为UTC(如果指定了时区),并存储为一个整数,表示自纪元以来的毫秒数。”
您可以定义自定义日期格式:
{
"mappings" : {
"properties" : {
"date" : {
"type" : "date" ,
"format" : "yyyy-MM-dd"
}
}
}
}
Elasticsearch支持其他字段类型,您可以在此处查看它们
建立我们的查询
每个查询均以“ query”子句开头
{
"query" : {
}
}
当查询Elasticsearch时,我们需要考虑两件事:
- 请记住,所有查询都是针对我们的倒排索引运行的。 我们为索引选择的分析器(内置或自定义)将影响我们的查询子句(小写字母,词干,删除停用词等)
- 每个字段的映射配置都会影响我们的查询。 例如:
- 文本字段-我们的字段配置为全文还是关键字?
- 日期-我们为该字段选择了哪种日期格式?
- 数字-我们的字段类型是整数,整型还是浮点型?
在编写查询时,我们可以使用两种子句:
- 复合查询子句 -这将是我们的包装子句,它们可以将Leaf查询和嵌套复合查询结合在一起。
- 叶子查询子句 -特定字段的查询词(字段名称和值)
复合查询子句
在开始编写复合查询之前,我们需要:
- 确定我们是否需要为每个文档打分? 得分将告诉我们每个文档相对于其他结果的相关性。
- 我们需要查询哪些字段? 哪些字段控制文档的分数?
首先,让我们了解弹性搜索中上下文的概念。
在elasticsearch中,我们有两种搜索环境:
查询上下文
在查询上下文中,查询子句回答问题“ 此文档与该查询子句的匹配程度如何?
”除了决定文档是否匹配外,查询子句还计算_score
元字段中的相关性得分。
官方文件
每当将查询子句传递给查询参数时,查询上下文即生效。 这可以是query
子句,例如布尔复合查询的must
, should
, must_not
子句。
elasticsearch纪录片在每个条款文件中都提到了是否有助于最终得分。
{
"query" : {
"bool" : {
"must" : [
{
"match" : {
"street" : "ditmas"
}
},
{
"match" : {
"street" : "avenue"
}
}
]
}
}
}
在上面的示例中,我们有一个must
子句。 查询上下文”表示其中的叶查询将影响匹配文档的分数。
这是计分算法背后的理论。
当您想按相关性对结果进行排序时,该分数非常有用。
筛选条件
在过滤器上下文中,查询子句回答问题“ 此文档是否与此查询子句匹配? 答案很简单,是或否-不计算分数。 过滤器上下文主要用于过滤结构化数据,例如
1.此timestamp
是否 在2015年到2016年之间?
2.status
字段是否设置为published
? 官方文件
每当将查询子句传递给过滤器参数时,过滤器上下文即生效。 例如,可以将filter
, must_not
参数传递给bool
复合查询。
像查询上下文一样,无论子句查询是否影响评分,都应查看文档。
{
"query" : {
"bool" : {
"filter" : {
"range" : {
"age" : {
"gte" : 20 ,
"lte" : 30
}
}
}
}
}
}
在上面的示例中,我们有一个名为“ Filter context”的filter
子句,这意味着其中的叶子查询不会影响匹配文档的分数。
在我们的搜索子句中,我们可以将查询和过滤器上下文与诸如bool
类的复合查询结合起来。 在这种情况下,只有出现在查询上下文子句中的搜索词才会影响每个文档的分数。 如果我们只有一个过滤器上下文,那么所有文档的分数都将为零。
我们之前做出的决定将确定查询的布局。
例如,此查询将查询上下文和过滤上下文一起使用:
{
"query" : {
"bool" : {
"must" : {
Leaf query clauses - affects the scoring of matching documents
},
"must_not" : {
Leaf query clauses - affects the scoring of matching documents
},
"should" : {
Leaf query clauses - affects the scoring of matching documents
},
"filter" : {
Leaf query clauses - doesn 't affects the scoring of matching documents
}
}
}
}
只有出现在must
内的查询子句must_not
should
子句会影响每个文档的分数(它们是查询上下文)。
Elasticsearch需要一个更匹配就是更好的办法意味着从得分must
, must_not
, should
将加在一起以提供最终得分。
如果我们根本不需要分数,则只能使用filter子句。 例如,如果我们搜索结构化数据或搜索诸如二进制或日期之类的确切值,我们将仅使用过滤器上下文:
{
"query" : {
"bool" : {
"filter" : [
{
"term" : { "gender" : "female" }
},
{
"range" : { "age" : { "gte" : "50" } }
}
]
}
}
}
上面查询结果中的所有匹配文档的得分均为零。
叶子查询子句
在构建外部布局时,我们决定了查询的构建基石。 我们还决定了哪些字段将决定我们的结果得分。 如您所见,elasticsearch有很多选项,我们仅介绍了本文的基础知识。 每个复合查询可以包装其他复合查询,依此类推。 我对您的建议是尝试使其尽可能简单。
现在是时候编写我们的内部/叶子搜索查询(容器子句中的内容)了。
在这里,我们还有决定要制定
对于我们搜索的每个字段,我们需要:
确定此字段是否与文档分数相关?
- 是的:将其放在
query
子句中 - 否:应在
filter
子句下(请注意,过滤器只能嵌套在Boolean子句中)
检查字段的类型以及如何映射?
- 例如,查询文本字段很棘手。 如果将文本字段映射为
keyword
,那么我们只能选择以对其进行索引的确切方式进行搜索(不标记,大写/小写字母等)。
比方说,例如,我们在一个带有“注释”字段的文档中建立了索引,并且其中包含文本“ The quick BRown fox”
- 如果
notes
字段被映射为Keyword,则反向索引将包含映射到该文档的“ Quick BRown fox”文本。 搜索“ Quick BRown fox”文本将完全匹配该文档。 - 如果将
notet
字段映射为全文,则在倒排索引中,我们将具有令牌:[the,quick,brown,fox]分别连接到文档-搜索这些令牌或其同义词将与该文档匹配。
确定如何将文本发送给搜索引擎
当我们将查询发送到elasticsearch引擎时,我们有两个选择:
1.按原样发送
对于这种选择,我们使用术语级别查询 。 例如,如果您搜索短语“ Star Trek”,则查询引擎将检查“ Star Trek”的倒排索引
2.发送分析
对于这种选择,我们使用全文查询 。 搜索的文本将与在索引过程中传递的索引文本通过同一分析器(我们也可以提供不同的分析器作为搜索服务的属性)。 它将被标记并过滤。 例如,如果您搜索短语“ Star Trek”,则查询引擎将检查[“ star”,“ trek”]的倒排索引(取决于您选择的分析仪)。
注意 :如果该字段最初是作为关键字映射的,那么您必须发送被索引的确切文本才能获得结果
在大多数情况下,我们希望在将搜索到的文本发送到搜索引擎之前对其进行分析,这样可以提供更好的结果。 但是有时我们想要搜索准确的单词或句子,通常是在数字,日期和枚举之类的数据中进行搜索。
全文查询示例
{
"query" : {
"match" : {
"mail_body" : "Jeff BRidges"
}
}
}
字词查询示例
{
"query" : {
"term" : {
"mail_from" : "emma@somemail.com"
}
}
}
复合查询-最后的详细示例
{
"query" : {
"bool" : {
"must" : {
"match" : {
"mail_body" : "Jeff BRidges"
}
},
"filter" : {
"term" : {
"mail_from" : "emma@somemail.com"
}
}
}
}
}
-
query:
主查询包含 -
bool
:复合查询容器 -
must
:这是一个查询上下文查询,它里面的每个叶子查询都会对匹配文档的分数做出贡献 -
match
:这是一个 全文查询,表示文本“ Jeff BRidges” 将通过 分析器并转换为[“ jeff”,“ bridges”]。 确保仅在“ mail_body”字段映射为全文字段时才使用该选项。 -
filter
:这是一个过滤器上下文查询,它里面的每个叶子查询都不会起作用 匹配文档的分数,并且考虑将子句缓存。 -
term
:这是一个 术语级别查询,则文本“ emma@somemail.com”将不会通过分析器,而是直接发送到搜索引擎。
最后的想法
Elasticsearch查询DSL绝对不是最简单的使用方法,但是一旦您知道如何使用它,它便可以成为功能强大的工具。 在本文中,我试图为大家提供一个查询Elasticsearch的快速入门,并鼓励您更深入地研究Elasticsearch文档 。
下一步
了解了本文中讨论的所有概念之后,您会发现遍历Elasticsearch文档并找到所需的所有解决方案变得更加容易。
From: https://hackernoon.com/how-to-master-elasticsearch-query-dsl-454632cg