
Elasticsearch 通常如何工作?
我们将文档索引到 Elasticsearch 中并对其运行查询以获得满足提供的搜索条件的文档。 我们构造一个匹配或术语查询作为输入,匹配查询的文档作为结果返回。
但这不是 percolate query 的情况.....
让我们看看这篇文章中的 percolate 查询,看看它有什么用处。
什么是 percolate 查询?
它与 Elasticsearch 搜索的一般工作方式相反。 在 Percolate Query 中,你将提供文档作为输入,以从与输入文档匹配的索引中查找 query。 可以根据已保存的查询使用 Percolate Query 对文档进行分类或标记。
Percolate query 调用 Elasticsearch 经典搜索的逆向 因为,
- query 将被存储而不是 Elasticsearch 索引中的文档。
- 文档将用于代替搜索请求中的 query。
Elasticsearch 将生成与输入文档匹配的查询列表。
 你可能想知道为什么我需要 Percolate 以及如何使用它? 因此,让我们看看下面的一些用例。
Percolate 用例
基于 percolate query 上面的描述,我们可以把它应用于如下的一些查询用例:
- 假设你正在开发一家在线商店,并提供在特定产品在特定价格范围内或以特定折扣上市时创建提醒的功能。
- 你正在创建推文或帖子分析,并且需要只考虑符合特定条款或条件的内容。 此外,每条满足特定要求的推文或帖子都需要使用特定标签进行标记。
Percolate query 实施
让我们通过一个在线商店用例来更详细地探索 Percolate。
假设消费者希望在 Apple iPhone 12 售价 500 美元时收到通知。
brand:apple AND price<500 AND model:'iphone 12'使用一些示例数据创建 products 索引:
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 索引:
必须将原始索引中的相同字段映射添加到 percolate 索引中。 只有需要搜索的字段必须从原始索引的映射中复制。
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:
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 美元。
POST products/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "brand.keyword": {
              "value": "Apple"
            }
          }
        },
        {
          "term": {
            "model.keyword": {
              "value": "iphone 12"
            }
          }
        },
        {
          "range": {
            "price": {
              "lte": 500
            }
          }
        }
      ]
    }
  }
}上面的搜索将返回如下的结果:
{
  "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:
POST product/_doc/prod104
{
  "brand": "Apple",
  "model": "iphone 12",
  "price": 499
}不会发送自动通知,因为在索引文档时不会运行 percolate 查询。 percolate 查询必须手动运行。
Percolate query API
你可以通过两种方式执行 percolate query:
首先,你可以使用单个文档或多个文档作为输入运行 percolate,如下所示:
单个文档
GET product_percolate/_search
{
  "query": {
    "percolate": {
      "field": "query",
      "document": {
        "brand": "Apple",
        "model": "iphone 12",
        "price": 499
      }
    }
  }
}多个文档
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 将显示在这种情况下多个文档中匹配的文档的位置。
{
  "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):
GET product_percolate/_search
{
  "query": {
    "percolate": {
      "field": "query",
      "index": "product",
      "id": "prod104"
    }
  }
}上面的查询的结果为:
{
  "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 与你的应用程序集成
- 如果你使用 Logstash 为数据编制索引,则可以使用 Elasticsearch 过滤器插件并运行过滤查询以查看传入文档是否与任何已保存的查询匹配。 如果是这样,你可以使用单独的输出插件向用户发送通知。
- 如果自定义连接器用于数据索引,则 Elastic 客户端可用于运行 percolate query 并直接从连接器发送通知。
为什么要 percolate 而不是 watcher?
相对于percolate,watcher 不太适合需要实时匹配的场景。 是的,相比之下还有更多的争论空间,但暂时,我认为这不在本博客的范围之内。
我希望本文能让你非常简单地掌握 percolate 查询。



![LeetCode[684]冗余连接](https://img-blog.csdnimg.cn/img_convert/c02bdcf7bcf2441196d3e09029eb0f3c.png)















