Elasticsearch:理解 Elasticsearch 中的 Percolator 数据类型及 Percolate 查询

Elasticsearch 是功能强大的功能丰富的工具。在今天的文章中,我来介绍一下 Percolator 数据类型。同时也介绍一下 Percolate query。 您需要基本了解 Elasticsearch,尤其是映射搜索

 

概念

lasticsearch 的正常工作流程是将文档(作为JSON数据)存储在索引中,并执行搜索(也是JSON数据)以向索引询问有关这些文档的信息。简而言之,Percolate 可以逆转这种情况。 你存储 search 吃并使用文档询问有关这些搜索的索引。 是的,但这并不是特别可行的信息。 多年来,如何构造 percolator,以至于我们可以给出更有用的解释。


现在,Percolation 围绕 percolator 映射字段类型展开。 与其他任何字段类型一样,不同的是它希望你将搜索文档分配为该值。 当你存储数据时,索引会将此搜索文档处理为可执行形式,并将其保存以备后用。


Percolate query 接受一个或多个文档,并将结果限制为那些存储的搜索至少匹配一个文档的文档。 搜索时,渗滤查询的工作原理与任何其他查询元素一样。

 

更深入的理解

在底层,这是以你期望的方式实现的:具有 percolate 字段的索引保留一个隐藏的(内存中)索引。首先,将在 percolate query 中列出的文档放入该索引,然后对该索引执行常规查询,以查看原始的含 percolate 字段的文档是否匹配。


要记住的重要一点是,该隐藏索引是从原始 percolator 索引获取其映射的。因此,用于 percolate query 的索引需要具有适合原始数据和查询文档数据的映射。


这引入了一些管理问题,因为你的索引数据和 percolate query 文档可能以不同的方式使用同一字段。一个简单的答案是使用对象类型 (object type) 将与 percolate 相关的映射与普通文档映射隔分开。


假设你使用的查询最初是为实际文档的另一个索引编写的,那么最直接的方法是将数据隔离衣避免数据直接写到 percolate 索引中去,并将根级别传递给 percolate query文档的映射定义。


另外,由于渗滤字段被解析为搜索并在索引时保存,因此你可能需要在升级后重新索引 Percolate 文档,以利用对系统的任何优化。

 

一个例子

在此示例中,我们将建立一个索引,该索引含有保存的玩具名字和玩具价格搜索。 其背后的想法是,用户应该能够输入搜索字词和最高价格,然后在与该字词匹配的商品价格低于此价格时立即得到通知。 用户还应该能够打开和关闭这些通知。下面的映射实现了 percolate 索引来支持此功能。 与保存的搜索本身相关的字段位于搜索对象中,而与原始玩具相关的字段位于映射的根级别。

首先,我们使用如下的命令来生产一个索引:

PUT toys
{
  "mappings": {
    "properties": {
      "search": {
        "properties": {
          "query": {
            "type": "percolator"
          },
          "user_id": {
            "type": "integer"
          },
          "enabled": {
            "type": "boolean"
          }
        }
      },
      "price": {
        "type": "float"
      },
      "description": {
        "type": "text"
      }
    }
  }
}

我们接着使用如下的命令写入一个文档:

PUT toys/_doc/1
{
  "search": {
    "user_id": 5,
    "enabled": true,
    "query": {
      "bool": {
        "filter": [
          {
            "match": {
              "description": {
                "query": "nintendo switch"
              }
            }
          },
          {
            "range": {
              "price": {
                "lte": 300
              }
            }
          }
        ]
      }
    }
  }
}

请注意,我们仅将数据存储在 search 对象字段中。 price 和 description 的映射仅用于支持 percolate query。
在查询时,我们要同时使用普通对象字段和“特殊” percolator 字段。 此查询将在用户搜索中检查是否有当前启用的搜索与文档匹配。

GET toys/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "percolate": {
            "field": "search.query",
            "document": {
              "description": "Nintendo Switch",
              "price": 250
            }
          }
        },
        {
          "term": {
            "search.enabled": true
          }
        },
        {
          "term": {
            "search.user_id": 5
          }
        }
      ]
    }
  }
}  

请注意,它结合了针对字段中存储的查询和常规术语查询的文档的 percolator 匹配,以限制基于其启用状态和用户ID测试的文档。运行上面的指令后,我们可以看到如下的结果:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.0,
    "hits" : [
      {
        "_index" : "toys",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.0,
        "_source" : {
          "search" : {
            "user_id" : 5,
            "enabled" : true,
            "query" : {
              "bool" : {
                "filter" : [
                  {
                    "match" : {
                      "description" : {
                        "query" : "nintendo switch"
                      }
                    }
                  },
                  {
                    "range" : {
                      "price" : {
                        "lte" : 300
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "fields" : {
          "_percolator_document_slot" : [
            0
          ]
        }
      }
    ]
  }
}

如果我们该用如下的搜索:

 

GET toys/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "percolate": {
            "field": "search.query",
            "document": {
              "description": "Nintendo Switch",
              "price": 500
            }
          }
        },
        {
          "term": {
            "search.enabled": true
          }
        },
        {
          "term": {
            "search.user_id": 5
          }
        }
      ]
    }
  }
}  

我们将找不到任何的结果:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 0,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  }
}

到现在为止,可能很多人也不一定知道到底为什么要用到这个 percolate query。在实际的使用中,我们可以在 Logstash 的 Elasticsearch 过滤器中针对每一个事件来针对 Elasticsearch 做 query。也即,我们可以知道这个事件是否满足其中的 search,如果是,将会丰富事件的数据。这个练习就留给你们来试。

 

参考:

【1】https://www.elastic.co/blog/elasticsearch-data-enrichment-with-logstash-a-few-security-examples

展开阅读全文
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值