我们将文档索引到 Elasticsearch 中并对其运行查询以获得满足提供的搜索条件的文档。 我们构造一个匹配或术语查询作为输入,匹配查询的文档作为结果返回。
但这不是 percolate query 的情况.....
让我们看看这篇文章中的 percolate 查询,看看它有什么用处。
它与 Elasticsearch 搜索的一般工作方式相反。 在 Percolate Query 中,你将提供文档作为输入,以从与输入文档匹配的索引中查找 query。 可以根据已保存的查询使用 Percolate Query 对文档进行分类或标记。
Percolate query 调用 Elasticsearch 经典搜索的逆向 因为,
Elasticsearch 将生成与输入文档匹配的查询列表。
你可能想知道为什么我需要 Percolate 以及如何使用它? 因此,让我们看看下面的一些用例。
基于 percolate query 上面的描述,我们可以把它应用于如下的一些查询用例:
让我们通过一个在线商店用例来更详细地探索 Percolate。
假设消费者希望在 Apple iPhone 12 售价 500 美元时收到通知。
1 |
brand:apple AND price<500 AND model:'iphone 12' |
使用一些示例数据创建 products 索引:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
` PUT products { "mappings": { "properties": { "brand": { "type": "text", "fields": { "keyword": { "type": "keyword" } } }, "model": { "type": "text", "fields": { "keyword": { "type": "keyword" } } }, "price": { "type": "long" } } } } PUT products/_bulk { "index" : { "_id": "prod101" } } { "brand" : "Apple", "model" : "iphone 11", "price": 800 } { "index" : { "_id": "prod102" } } { "brand" : "Samsung", "model" : "galaxy m32", "price": 700 } ` |
必须将原始索引中的相同字段映射添加到 percolate 索引中。 只有需要搜索的字段必须从原始索引的映射中复制。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
` PUT product_percolate { "mappings": { "properties": { "query": { "type": "percolator" }, "brand": { "type": "text", "fields": { "keyword": { "type": "keyword" } } }, "model": { "type": "text", "fields": { "keyword": { "type": "keyword" } } }, "price": { "type": "long" } } } } ` |
让我们保存一个用户想要提醒的 query:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
` PUT product_percolate/_doc/user1_iphone_12 { "query": { "bool": { "must": [ { "term": { "brand.keyword": { "value": "Apple" } } }, { "term": { "model.keyword": { "value": "iphone 12" } } }, { "range": { "price": { "lte": 500 } } } ] } } } ` |
现在进行产品查询时,将不会返回任何结果,因为所有 iPhone 12 不低于 500 美元。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
` POST products/_search { "query": { "bool": { "must": [ { "term": { "brand.keyword": { "value": "Apple" } } }, { "term": { "model.keyword": { "value": "iphone 12" } } }, { "range": { "price": { "lte": 500 } } } ] } } } ` |
上面的搜索将返回如下的结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
` { "took": 1, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 0, "relation": "eq" }, "max_score": null, "hits": [] } } ` |
上面的结果表明,没有一个产品满足我们的搜索条件。
让我们添加价格为 499 的新产品 iPhone 12:
1 2 3 4 5 6 |
POST product/_doc/prod104 { "brand": "Apple", "model": "iphone 12", "price": 499 } |
不会发送自动通知,因为在索引文档时不会运行 percolate 查询。 percolate 查询必须手动运行。
你可以通过两种方式执行 percolate query:
首先,你可以使用单个文档或多个文档作为输入运行 percolate,如下所示:
单个文档
1 2 3 4 5 6 7 8 9 10 11 12 13 |
GET product_percolate/_search { "query": { "percolate": { "field": "query", "document": { "brand": "Apple", "model": "iphone 12", "price": 499 } } } } |
多个文档
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
` GET product_percolate/_search { "query": { "percolate": { "field": "query", "documents": [ { "brand": "Apple", "model": "iphone 12 pro", "price": 600 }, { "brand": "Apple", "model": "iphone 12", "price": 499 } ] } } } ` |
你将收到类似于正常查询响应的响应,字段 _source 将显示匹配的查询,但字段 _percolator_document_slot 将显示在这种情况下多个文档中匹配的文档的位置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
` { "took": 3, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 1, "relation": "eq" }, "max_score": 1.2615292, "hits": [ { "_index": "product_percolate", "_id": "user1_iphone_12", "_score": 1.2615292, "_source": { "query": { "bool": { "must": [ { "term": { "brand.keyword": { "value": "Apple" } } }, { "term": { "model.keyword": { "value": "iphone 12" } } }, { "range": { "price": { "lte": 500 } } } ] } } }, "fields": { "_percolator_document_slot": [ 0 ] } } ] } } ` |
其次,你可以提供现有索引中的文档 ID,如下所示(目前不支持传递多个 ID):
1 2 3 4 5 6 7 8 9 10 |
GET product_percolate/_search { "query": { "percolate": { "field": "query", "index": "product", "id": "prod104" } } } |
上面的查询的结果为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
` { "took": 7, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 1, "relation": "eq" }, "max_score": 1.2615292, "hits": [ { "_index": "product_percolate", "_id": "user1_iphone_12", "_score": 1.2615292, "_source": { "query": { "bool": { "must": [ { "term": { "brand.keyword": { "value": "Apple" } } }, { "term": { "model.keyword": { "value": "iphone 12" } } }, { "range": { "price": { "lte": 500 } } } ] } } }, "fields": { "_percolator_document_slot": [ 0 ] } } ] } } ` |
相对于percolate,watcher 不太适合需要实时匹配的场景。 是的,相比之下还有更多的争论空间,但暂时,我认为这不在本博客的范围之内。