Elasticsearch:Elasticsearch 查询示例 – 动手练习(一)
2022年2月24日 | by mebius
在我之前的文章文章:
我列举了很多关于 Elasticsearch 查询的例子。抱着多多益善的想法,在今天的文章中,我给大家带来更多的例子给大家练习。希望大家对 Elasticsearch 有更多的认识。
Elasticsearch 提供了一组强大的选项来查询各种用例的文档,因此了解将哪个查询应用于特定案例很有用。 以下是一个动手教程,可帮助你利用 Elasticsearch 提供的最重要的查询。
在本指南中,你将学习许多带有详细解释的流行查询示例。 此处涵盖的每个查询将分为 2 种类型:
- 结构化查询:用于检索结构化数据的查询,例如日期、数字、密码等。
- 全文查询:用于查询纯文本的查询。
请注意:在本文章中, 我将使用最新的 Elastic Stack 7.16.3 发布来进行展示。有于文章比较长,所以分为两个部分:
设置演示索引
让我们首先使用一些示例数据创建一个新索引,以便你可以按照每个搜索示例进行操作。创建一个名为 “employees” 的索引:
PUT employees
为包含在摄入文档中的字段 (比如,date_of_birth) 定义映射(模式):
PUT employees/_mapping
{
"properties": {
"date_of_birth": {
"type": "date",
"format": "dd/MM/yyyy"
}
}
}
上面显示,我们文档的日期格式是 dd/MM/yyyy。
现在让我们将一些文档摄入到我们新创建的索引中,如下面的示例所示,使用 Elasticsearch 的 _bulk API:
POST _bulk
{"index":{"_index":"employees","_id":"1"}}
{"id":1,"name":"Huntlee Dargavel","email":"hdargavel0@japanpost.jp","gender":"male","ip_address":"58.11.89.193","date_of_birth":"11/09/1990","company":"Talane","position":"Research Associate","experience":7,"country":"China","phrase":"Multi-channelled coherent leverage","salary":180025}
{"index":{"_index":"employees","_id":"2"}}
{"id":2,"name":"Othilia Cathel","email":"ocathel1@senate.gov","gender":"female","ip_address":"3.164.153.228","date_of_birth":"22/07/1987","company":"Edgepulse","position":"Structural Engineer","experience":11,"country":"China","phrase":"Grass-roots heuristic help-desk","salary":193530}
{"index":{"_index":"employees","_id":"3"}}
{"id":3,"name":"Winston Waren","email":"wwaren2@4shared.com","gender":"male","ip_address":"202.37.210.94","date_of_birth":"10/11/1985","company":"Yozio","position":"Human Resources Manager","experience":12,"country":"China","phrase":"Versatile object-oriented emulation","salary":50616}
{"index":{"_index":"employees","_id":"4"}}
{"id":4,"name":"Alan Thomas","email":"athomas2@example.com","gender":"male","ip_address":"200.47.210.95","date_of_birth":"11/12/1985","company":"Yamaha","position":"Resources Manager","experience":12,"country":"China","phrase":"Emulation of roots heuristic coherent systems","salary":300000}
现在我们已经有了一个包含文档的索引和一个指定的映射,我们已经准备好开始使用示例搜索了。为方便大家阅读,我把其中的一个文档的字段列出来:
GET employees/_doc/1?filter_path=_source
{
"_source" : {
"id" : 1,
"name" : "Huntlee Dargavel",
"email" : "hdargavel0@japanpost.jp",
"gender" : "male",
"ip_address" : "58.11.89.193",
"date_of_birth" : "11/09/1990",
"company" : "Talane",
"position" : "Research Associate",
"experience" : 7,
"country" : "China",
"phrase" : "Multi-channelled coherent leverage",
"salary" : 180025
}
}
从上面的返回数据中,我们可以看到包含在每个文档中的字段。整个索引我们只包含4个文档,但是它足以让我们了解各个搜索。较少的数据集可以让我们看得更加清楚。
Match query
“match” 查询 是 Elasticsearch 中最基本、最常用的查询之一,起到全文查询的作用。 我们可以使用这个查询来搜索文本、数字或布尔值。
让我们在之前提取的文档中搜索名为 “phrase” 的字段中包含的单词 “heuristic”。
POST employees/_search
{
"query": {
"match": {
"phrase": {
"query": "heuristic"
}
}
}
}
在我们索引中的 4 个文档中,只有 2 个文档中的“phrase” 字段中的包含 “heuristic”一词:
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 0.6785375,
"hits" : [
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "2",
"_score" : 0.6785375,
"_source" : {
"id" : 2,
"name" : "Othilia Cathel",
"email" : "ocathel1@senate.gov",
"gender" : "female",
"ip_address" : "3.164.153.228",
"date_of_birth" : "22/07/1987",
"company" : "Edgepulse",
"position" : "Structural Engineer",
"experience" : 11,
"country" : "China",
"phrase" : "Grass-roots heuristic help-desk",
"salary" : 193530
}
},
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "4",
"_score" : 0.62577873,
"_source" : {
"id" : 4,
"name" : "Alan Thomas",
"email" : "athomas2@example.com",
"gender" : "male",
"ip_address" : "200.47.210.95",
"date_of_birth" : "11/12/1985",
"company" : "Yamaha",
"position" : "Resources Manager",
"experience" : 12,
"country" : "China",
"phrase" : "Emulation of roots heuristic coherent systems",
"salary" : 300000
}
}
]
}
}
如果我们要搜索多个单词会发生什么? 使用我们刚刚执行的相同查询,让我们搜索 “heuristic roots help”:
POST employees/_search
{
"query": {
"match": {
"phrase": {
"query": "heuristic roots help"
}
}
}
}
这将返回与以前相同的文档,因为默认情况下,Elasticsearch 使用 OR 运算符处理搜索查询中的每个单词。 在我们的例子中,查询将匹配任何包含 “heuristic” 或 “roots” 或 “help” 的文档。
应用于多词搜索的 OR 运算符是 match 的默认行为,但是我们可以使用与 “match” 查询一起传递的 “operator” 参数来更改。我们可以使用 “OR” 或 “AND” 值指定 operator 参数。
让我们看看当我们在之前执行的同一查询中提供运算符参数 “AND” 时会发生什么。
POST employees/_search
{
"query": {
"match": {
"phrase": {
"query": "heuristic roots help",
"operator": "AND"
}
}
}
}
现在结果将只返回一个文档(文档 id=2),因为这是在 “phrase” 字段中同时包含所有三个搜索关键字的唯一文档。
minimum_should_match
更进一步,我们可以为文档必须包含的最小匹配词设置一个阈值。 例如,如果我们将此参数设置为 1,则查询将检查至少有 1 个匹配词的任何文档。
现在,如果我们将 “minium_should_match” 参数设置为 3,那么所有三个单词都必须出现在文档中才能被归类为匹配项。
在我们的例子中,以下查询将仅返回 1 个文档(id=2),因为它是唯一符合我们条件的文档:
POST employees/_search
{
"query": {
"match": {
"phrase": {
"query" : "heuristic roots help",
"minimum_should_match": 3
}
}
}
}
Mulit-Match Query
到目前为止,我们一直在处理单个字段上的匹配项——也就是说,我们在名为 “phrase” 的单个字段中搜索关键字。但是,如果我们需要在文档的多个字段中搜索关键字怎么办? 这就是多匹配(multi-match)查询发挥作用的地方。
让我们尝试在文档中包含的 “position” 和 “phrase” 字段中搜索关键字 “research help” 的示例。
POST employees/_search
{
"query": {
"multi_match": {
"query": "research help",
"fields": [
"position",
"phrase"
]
}
}
}
这将导致以下响应:
{
"took" : 24,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 1.2613049,
"hits" : [
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.2613049,
"_source" : {
"id" : 1,
"name" : "Huntlee Dargavel",
"email" : "hdargavel0@japanpost.jp",
"gender" : "male",
"ip_address" : "58.11.89.193",
"date_of_birth" : "11/09/1990",
"company" : "Talane",
"position" : "Research Associate",
"experience" : 7,
"country" : "China",
"phrase" : "Multi-channelled coherent leverage",
"salary" : 180025
}
},
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "2",
"_score" : 1.1785964,
"_source" : {
"id" : 2,
"name" : "Othilia Cathel",
"email" : "ocathel1@senate.gov",
"gender" : "female",
"ip_address" : "3.164.153.228",
"date_of_birth" : "22/07/1987",
tgcode "company" : "Edgepulse",
"position" : "Structural Engineer",
"experience" : 11,
"country" : "China",
"phrase" : "Grass-roots heuristic help-desk",
"salary" : 193530
}
}
]
}
}
从上面的结果中,我们可以看出来任何在 position 或 phrase 字段包含research 或者 help 的文档都将被搜索到。
Match Phrase
Match_phrase 是另一种常用的查询,正如其名称所示,它匹配字段中的短语。
如果我们需要在员工索引的 “phrase” 字段中搜索短语 “roots heuristic coherent”,我们可以使用 “match_phrase” 查询:
GET employees/_search
{
"query": {
"match_phrase": {
"phrase": {
"query": "roots heuristic coherent"
}
}
}
}
这将返回具有确切短语 “roots heuristic coherent” 的文档,包括单词的顺序。 在我们的例子中,我们只有一个符合上述条件的结果,如下面的响应所示:
{
"took" : 23,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.877336,
"hits" : [
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "4",
"_score" : 1.877336,
"_source" : {
"id" : 4,
"name" : "Alan Thomas",
"email" : "athomas2@example.com",
"gender" : "male",
"ip_address" : "200.47.210.95",
"date_of_birth" : "11/12/1985",
"company" : "Yamaha",
"position" : "Resources Manager",
"experience" : 12,
"country" : "China",
"phrase" : "Emulation of roots heuristic coherent systems",
"salary" : 300000
}
}
]
}
}
slop 参数
我们可以在 match_phrase 查询中使用的一个有用功能是 “slop” 参数,它允许我们创建更灵活的搜索。
假设我们使用 match_phrase 查询搜索 “roots coherent”。 我们不会收到从员工索引返回的任何文档。 这是因为要匹配 match_phrase,这些术语需要按照准确的顺序排列。
现在,让我们使用 slop 参数,看看会发生什么:
GET employees/_search
{
"query": {
"match_phrase": {
"phrase": {
"query": "roots coherent",
"slop": 1
}
}
}
}
当 slop=1 时,查询表明可以移动一个单词进行匹配,因此我们将收到以下响应。 在下面的响应中,你可以看到 “roots coherent” 与 “roots heuristic coherent” 文档相匹配。 这是因为 slop 参数允许跳过 1 个术语。
{
"took" : 3,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.7873249,
"hits" : [
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "4",
"_score" : 0.7873249,
"_source" : {
"id" : 4,
"name" : "Alan Thomas",
"email" : "athomas2@example.com",
"gender" : "male",
"ip_address" : "200.47.210.95",
"date_of_birth" : "11/12/1985",
"company" : "Yamaha",
"position" : "Resources Manager",
"experience" : 12,
"country" : "China",
"phrase" : "Emulation of roots heuristic coherent systems",
"salary" : 300000
}
}
]
}
}
Match Phrase Prefix
match_phrase_prefix 查询类似于 match_phrase 查询,但这里将搜索关键字的最后一个词视为前缀,用于匹配以该前缀词开头的任何词。
首先,让我们在索引中插入一个文档,以更好地理解 match_phrase_prefix 查询:
PUT employees/_doc/5
{
"id": 4,
"name": "Jennifer Lawrence",
"email": "jlaw@example.com",
"gender": "female",
"ip_address": "100.37.110.59",
"date_of_birth": "17/05/1995",
"company": "Monsnto",
"position": "Resources Manager",
"experience": 10,
"country": "Germany",
"phrase": "Emulation of roots heuristic complete systems",
"salary": 300000
}
现在让我们应用 match_phrase_prefix:
GET employees/_search
{
"_source": [
"phrase"
],
"query": {
"match_phrase_prefix": {
"phrase": {
"query": "roots heuristic co"
}
}
}
}
在下面的结果中,我们可以看到具有 coherent 和 complete 的文档与查询匹配。 我们还可以在 “match_phrase” 查询中使用 slop 参数。
{
"took" : 61,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 3.0871696,
"hits" : [
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "4",
"_score" : 3.0871696,
"_source" : {
"phrase" : "Emulation of roots heuristic coherent systems"
}
},
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "5",
"_score" : 3.0871696,
"_source" : {
"phrase" : "Emulation of roots heuristic complete systems"
}
}
]
}
}
注意:“match_phrase_query” 尝试匹配最后提供的关键字(在我们的示例中为 co)的 50 个扩展(默认情况下),也就是说搜索到包含有 co 的50个结果。这可以通过指定 “max_expansions” 参数来增加或减少。
GET employees/_search
{
"_source": [
"phrase"
],
"query": {
"match_phrase_prefix": {
"phrase": {
"query": "roots heuristic co",
"max_expansions": 1
}
}
}
}
比如,上面的查询将只返回一个文档:
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.805721,
"hits" : [
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "4",
"_score" : 1.805721,
"_source" : {
"phrase" : "Emulation of roots heuristic coherent systems"
}
}
]
}
}
由于这个前缀属性和 match_phrase_prefix 查询的易于设置的属性,它通常用于自动完成功能。
现在让我们删除刚刚添加的 id=5 的文档:
DELETE employees/_doc/5
Term 级查询
术语级查询用于查询结构化数据,通常是精确值。
Term Query/Terms Query
这是最简单的术语级别查询。 此查询针对文档中的字段搜索搜索关键字(keyword)的完全匹配。
例如,如果我们对 “gender” 字段使用术语查询来搜索 “Male” 这个词,它会完全按照这个词进行搜索,即使有大小写也是如此。
这可以通过以下两个查询来证明:
GET employees/_search
{
"query": {
"term": {
"gender": {
"value": "female"
}
}
}
}
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 0.87546873,
"hits" : [
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "2",
"_score" : 0.87546873,
"_source" : {
"id" : 2,
"name" : "Othilia Cathel",
"email" : "ocathel1@senate.gov",
"gender" : "female",
"ip_address" : "3.164.153.228",
"date_of_birth" : "22/07/1987",
"company" : "Edgepulse",
"position" : "Structural Engineer",
"experience" : 11,
"country" : "China",
"phrase" : "Grass-roots heuristic help-desk",
"salary" : 193530
}
},
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "5",
"_score" : 0.87546873,
"_source" : {
"id" : 4,
"name" : "Jennifer Lawrence",
"email" : "jlaw@example.com",
"gender" : "female",
"ip_address" : "100.37.110.59",
"date_of_birth" : "17/05/1995",
"company" : "Monsnto",
"position" : "Resources Manager",
"experience" : 10,
"country" : "Germany",
"phrase" : "Emulation of roots heuristic complete systems",
"salary" : 300000
}
}
]
}
}
上面的搜索返回有两个结果。如果我们做如下的查询:
GET employees/_search
{
"query": {
"term": {
"gender": {
"value": "Female"
}
}
}
}
在上面,我们把 female 修改为 Female,那么我们将搜索不到任何的文档。在上述情况下,两个查询之间的唯一区别是搜索关键字的大小写不同。 案例 1 全部为小写,这是匹配的,因为这个字段的值就是按照小写保存的。 但是对于案例 2,搜索没有得到任何结果,因为没有针对带有大写 “F” 的 “gender” 字段的此类 token。
我们还可以使用 terms query传递多个要在同一字段上搜索的术语。 让我们在性别字段中搜索 “female” 和 “male”。 为此,我们可以使用以下 terms query:
POST employees/_search
{
"query": {
"terms": {
"gender": [
"female",
"male"
]
}
}
}
上面的查询将返回所有的4个文档。
Exists 查询
有时会发生字段没有索引值,或者文档中不存在该字段。 在这种情况下,它有助于识别此类文件并分析影响。
例如,让我们将下面的文档索引到 “employee” 索引
PUT employees/_doc/5
{
"id": 5,
"name": "Michael Bordon",
"email": "mbordon@example.com",
"gender": "male",
"ip_address": "10.47.210.65",
"date_of_birth": "12/12/1995",
"position": "Resources Manager",
"experience": 12,
"country": null,
"phrase": "Emulation of roots heuristic coherent systems",
"salary": 300000
}
此文档没有名为 “company” 的字段,并且 “country” 字段的值为 null。
现在,如果我们想查找字段为 “company” 的文档,我们可以使用如下的 exist 查询:
GET employees/_search
{
"query": {
"exists": {
"field": "company"
}
}
}
上面的查询将列出所有具有 “company” 字段的文档。上面查询的结果将返回4个文档,并且它们都含有 company 字段。而 id=5 的文档不被搜索到。
也许更有用的解决方案是列出所有没有 “company” 字段的文档。 这也可以通过使用如下的存在查询来实现:
GET employees/_search
{
"query": {
"bool": {
"must_not": [
{
"exists": {
"field": "company"
}
}
]
}
}
}
bool 查询将在以下部分中详细说明。上面的查询将只返回 id=5 的文档:
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.0,
"hits" : [
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "5",
"_score" : 0.0,
"_source" : {
"id" : 5,
"name" : "Michael Bordon",
"email" : "mbordon@example.com",
"gender" : "male",
"ip_address" : "10.47.210.65",
"date_of_birth" : "12/12/1995",
"position" : "Resources Manager",
"experience" : 12,
"country" : null,
"phrase" : "Emulation of roots heuristic coherent systems",
"salary" : 300000
}
}
]
}
}
让我们从索引中删除现在插入的文档,为了方便和统一,通过键入以下请求:
DELETE employees/_doc/5
Range queries
Elasticsearch 世界中另一个最常用的查询是范围查询。 范围查询允许我们获取包含指定范围内的术语的文档。 范围查询是术语级别的查询(表示用于查询结构化数据),可用于数值字段、日期字段等。
数值字段的 range 查询
例如,在我们创建的数据集中,如果我们需要过滤掉 experience 水平在 5 到 10 年之间的人,我们可以对其应用以下范围查询:
POST employees/_search
{
"query": {
"range": {
"experience": {
"gte": 5,
"lte": 10
}
}
}
}
什么是 gte、gt、lt 和 lt?
- gte 大于等于,gte: 5 表示大于等于5,其中包括5。greater than or equal to
- gt 大于,gt: 5 ,表示大于5,不包括5。greater than
- lte 小于或等于,lte: 5 ,表示小于等于5,其中包括5。less than or equal to
- lt 小于,less than
- gt: 5 ,表示小于5,不包括5。greater than
上面查询的结果为:
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"id" : 1,
"name" : "Huntlee Dargavel",
"email" : "hdargavel0@japanpost.jp",
"gender" : "male",
"ip_address" : "58.11.89.193",
"date_of_birth" : "11/09/1990",
"company" : "Talane",
"position" : "Research Associate",
"experience" : 7,
tgcode "country" : "China",
"phrase" : "Multi-channelled coherent leverage",
"salary" : 180025
}
}
]
}
}
也就是说 experience 在 5 和 10 之间的只有一个文档。
日期字段的 range query
同样,范围查询也可以应用于日期字段。 如果我们需要找出 1986 年之后出生的人,我们可以发出如下所示的查询:
GET employees/_search
{
"query": {
"range" : {
"date_of_birth" : {
"gte" : "01/01/1986"
}
}
}
}
这将为我们获取仅在 1986 年之后具有 date_of_birth 字段的文档。
Ids queries
ids 查询是一个相对较少使用的查询,但它是最有用的查询之一,因此有资格在此列表中。 有时我们需要根据文档的 ID 来检索文档。 这可以使用单个 get 请求来实现,如下所示:
GET indexname/_doc/documentId
如果一个 ID 只能获取一个文档,这可能是一个很好的解决方案,但是如果我们有更多文档怎么办?
这就是 ids 查询非常方便的地方。 使用 Ids 查询,我们可以在单个请求中完成此操作。
在下面的示例中,我们通过单个请求从 employees 索引中获取 id 为 1 和 4 的文档。
POST employees/_search
{
"query": {
"ids" : {
"values" : ["1", "4"]
}
}
}
上面查询将返回:
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"id" : 1,
"name" : "Huntlee Dargavel",
"email" : "hdargavel0@japanpost.jp",
"gender" : "male",
"ip_address" : "58.11.89.193",
"date_of_birth" : "11/09/1990",
"company" : "Talane",
"position" : "Research Associate",
"experience" : 7,
"country" : "China",
"phrase" : "Multi-channelled coherent leverage",
"salary" : 180025
}
},
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "4",
"_score" : 1.0,
"_source" : {
"id" : 4,
"name" : "Alan Thomas",
"email" : "athomas2@example.com",
"gender" : "male",
"ip_address" : "200.47.210.95",
"date_of_birth" : "11/12/1985",
"company" : "Yamaha",
"position" : "Resources Manager",
"experience" : 12,
"country" : "China",
"phrase" : "Emulation of roots heuristic coherent systems",
"salary" : 300000
}
}
]
}
}
Prefix Queries
前缀查询(Prefix query)用于获取包含给定搜索字符串作为指定字段前缀的文档。
假设我们需要在 “name” 字段中获取所有包含 “al” 作为前缀的文档,那么我们可以使用前缀查询如下:
GET employees/_search
{
"query": {
"prefix": {
"name": "al"
}
}
}
这将导致以下响应:
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "4",
"_score" : 1.0,
"_source" : {
"id" : 4,
"name" : "Alan Thomas",
"email" : "athomas2@example.com",
"gender" : "male",
"ip_address" : "200.47.210.95",
"date_of_birth" : "11/12/1985",
"company" : "Yamaha",
"position" : "Resources Manager",
"experience" : 12,
"country" : "China",
"phrase" : "Emulation of roots heuristic coherent systems",
"salary" : 300000
}
}
]
}
}
由于前缀查询是一个术语查询,它将按原样传递搜索字符串。 那就是搜索 “al” 和 “Al” 是不同的。 如果在上面的示例中,我们搜索 “Al”,我们将得到 0 个结果,因为在 “name” 字段的倒排索引中没有以 “Al” 开头的 token。 但是,如果我们查询“name.keyword”字段,使用 “Altgcode” 我们将得到上述结果,在这种情况下,查询 “al” 将导致零命中。
Wildcard quieries
这个也叫做通配符查询(wildcard query)。将获取具有与给定通配符模式匹配的术语的文档。例如,让我们在字段 “country” 上使用通配符查询来搜索 “c*a”,如下所示:
GET employees/_search
{
"query": {
"wildcard": {
"country": {
"value": "c*a"
}
}
}
}
上面的查询将获取所有以 “c” 开头并以 “a” 结尾的 “country” 名称的文档(例如:China、Canada、Cambodia 等)。
这里 * 运算符可以匹配零个或多个字符。
Regexp
这个是正则查询。这类似于我们上面看到的 “通配符” 查询,但将接受正则表达式作为输入并获取匹配的文档。
GET employees/_search
{
"query": {
"regexp": {
"position": "res[a-z]*"
}
}
}
上面的查询将得到匹配正则表达式 res[a-z]* 的单词的文档。
{
"took" : 3,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 3,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"id" : 1,
"name" : "Huntlee Dargavel",
"email" : "hdargavel0@japanpost.jp",
"gender" : "male",
"ip_address" : "58.11.89.193",
"date_of_birth" : "11/09/1990",
"company" : "Talane",
"position" : "Research Associate",
"experience" : 7,
"country" : "China",
"phrase" : "Multi-channelled coherent leverage",
"salary" : 180025
}
},
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "3",
"_score" : 1.0,
"_source" : {
"id" : 3,
"name" : "Winston Waren",
"email" : "wwaren2@4shared.com",
"gender" : "male",
"ip_address" : "202.37.210.94",
"date_of_birth" : "10/11/1985",
"company" : "Yozio",
"position" : "Human Resources Manager",
"experience" : 12,
"country" : "China",
"phrase" : "Versatile object-oriented emulation",
"salary" : 50616
}
},
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "4",
"_score" : 1.0,
"_source" : {
"id" : 4,
"name" : "Alan Thomas",
"email" : "athomas2@example.com",
"gender" : "male",
"ip_address" : "200.47.210.95",
"date_of_birth" : "11/12/1985",
"company" : "Yamaha",
"position" : "Resources Manager",
"experience" : 12,
"country" : "China",
"phrase" : "Emulation of roots heuristic coherent systems",
"salary" : 300000
}
}
]
}
}
Fuzzy
模糊查询可用于返回包含与搜索词相似的词的文档。 这在处理拼写错误时尤其有用。即使我们使用模糊查询搜索 “Chnia” 而不是“China”,我们也可以获得结果。
让我们看一个例子:
GET employees/_search
{
"query": {
"fuzzy": {
"country": {
"value": "Chnia",
"fuzziness": "2"
}
}
}
}
这里的模糊度是匹配允许的最大编辑距离。 我们在 “match_phrase” 查询中看到的 “max_expansions” 等参数也可以使用。 更多相关文档可以在这里找到
模糊查询也可以与 “match” 查询类型一起出现。 以下示例显示了在 multi_match 查询中使用的模糊性:
POST employees/_search
{
"query": {
"multi_match": {
"query": "heursitic reserch",
"fields": [
"phrase",
"position"
],
"fuzziness": 2
}
},
"size": 10
}
尽管查询中存在拼写错误,上述查询仍将返回匹配 “heuristic” 或 “research” 的文档。
Boosting
在查询时,首先获得更受欢迎的结果通常会有所帮助。 执行此操作的最简单方法在 Elasticsearch 中称为 boosting。 当我们查询多个字段时,这会派上用场。 例如,考虑以下查询:
POST employees/_search
{
"query": {
"multi_match" : {
"query" : "versatile Engineer",
"fields": ["position^3", "phrase"]
}
}
}
这将返回与 “position” 字段匹配的文档位于顶部的响应,而不是与“phrase”字段匹配的文档。
Sorting – 排序
默认排序
当搜索请求中没有指定排序参数时,Elasticsearch 根据 “_score” 字段的降序返回文档。 这个“_score”是根据使用 Elasticsearch 的默认评分方法的查询匹配程度来计算的。 在我们上面讨论的所有示例中,你可以在结果中看到相同的行为。
只有当我们使用 “filter” 上下文时,才不会计算评分,以便更快地返回结果。
如何根据字段来进行排名
Elasticsearch 为我们提供了基于字段进行排序的选项。 比如说,让我们需要根据员工的经验降序对员工进行排序。 我们可以使用启用了排序选项的以下查询来实现:
GET employees/_search
{
"_source": [
"name",
"experience",
"salary"
],
"sort": [
{
"experience": {
"order": "desc"
}
}
]
}
上述查询的结果如下:
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 4,
"relation" : "eq"
},
"max_score" : null,
"hits" : [
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "3",
"_score" : null,
"_source" : {
"name" : "Winston Waren",
"experience" : 12,
"salary" : 50616
},
"sort" : [
12
]
},
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "4",
"_score" : null,
"_source" : {
"name" : "Alan Thomas",
"experience" : 12,
"salary" : 300000
},
"sort" : [
12
]
},
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "2",
"_score" : null,
"_source" : {
"name" : "Othilia Cathel",
"experience" : 11,
"salary" : 193530
},
"sort" : [
11
]
},
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "1",
"_score" : null,
"_source" : {
"name" : "Huntlee Dargavel",
"experience" : 7,
"salary" : 180025
},
"sort" : [
7
]
}
]
}
}
从上面的响应中可以看出,结果是根据员工体验的降序排列的。此外,还有两名员工,他们的经验水平与 12 级相同。
如何根据多字段来进行排名
在上面的示例中,我们看到有两个员工的经验等级相同,均为 12,但我们需要根据薪水的降序再次排序。 我们也可以提供多个字段进行排序,如下面的查询所示:
GET employees/_search?filter_path=**.hits
{
"_source": [
"name",
"experience",
"salary"
],
"sort": [
{
"experience": {
"order": "desc"
}
},
{
"salary": {
"order": "desc"
}
}
]
}
现在我们得到以下结果:
{
"hits" : {
"hits" : [
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "4",
"_score" : null,
"_source" : {
"name" : "Alan Thomas",
"experience" : 12,
"salary" : 300000
},
"sort" : [
12,
300000
]
},
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "3",
"_score" : null,
"_source" : {
"name" : "Winston Waren",
"experience" : 12,
"salary" : 50616
},
"sort" : [
12,
50616
]
},
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "2",
"_score" : null,
"_source" : {
"name" : "Othilia Cathel",
"experience" : 11,
"salary" : 193530
},
"sort" : [
11,
193530
]
},
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "1",
"_score" : null,
"_source" : {
"name" : "Huntlee Dargavel",
"experience" : 7,
"salary" : 180025
},
"sort" : [
7,
180025
]
}
]
}
}
在上面的结果中,你可以看到,在具有相同经验级别的员工中,薪水最高的人在订单中被提前了(Alan 和 Winston 的经验级别相同,但与之前的搜索结果不同,这里 Alan 的排名被提升因为他的薪水更高)。
注意:如果我们改变排序数组中排序参数的顺序,即先保留 “salary” 参数,然后保留 “experience” 参数,那么搜索结果也会发生变化。 结果将首先根据薪水参数进行排序,然后将考虑经验参数,而不影响基于薪水的排序。
让我们将上述查询的排序顺序颠倒一下,即先保留 “salary”,然后是“experience”,如下所示:
GET employees/_search?filter_path=**.hits
{
"_source": [
"name",
"experience",
"salary"
],
"sort": [
{
"salary": {
"order": "desc"
}
},
{
"experience": {
"order": "desc"
}
}
]
}
结果如下:
{
"hits" : {
"hits" : [
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "4",
"_score" : null,
"_source" : {
"name" : "Alan Thomas",
"experience" : 12,
"salary" : 300000
},
"sort" : [
300000,
12
]
},
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "2",
"_score" : null,
"_source" : {
"name" : "Othilia Cathel",
"experience" : 11,
"salary" : 193530
},
"sort" : [
193530,
11
]
},
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "1",
"_score" : null,
"_source" : {
"name" : "Huntlee Dargavel",
"experience" : 7,
"salary" : 180025
},
"sort" : [
180025,
7
]
},
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "3",
"_score" : null,
"_source" : {
"name" : "Winston Waren",
"experience" : 12,
"salary" : 50616
},
"sort" : [
50616,
12
]
}
]
}
}
你可以看到经验值 12 的候选人低于经验值 7 的候选人,因为后者的薪水高于前者。
文章来源于互联网:Elasticsearch:Elasticsearch 查询示例 – 动手练习(一)
相关推荐: 使用 Elastic Stack 来分析奥运数据(一)
最近冬奥会在中国北京顺利举行。这是一件举国高兴的事。在历届都有许多的奥运数据,我们是否可以使用 Elastic Stack 来分析这些数据,并为我国的体育事业提供一些洞察呢? 最近,孩子学校布置了一个寒假的科技信息作业。内容如下: 1、使用网络及其他方式,完成…