【问题标题】:Elasticsearch - Return a subset of nested resultsElasticsearch - 返回嵌套结果的子集
【发布时间】:2020-06-23 19:25:44
【问题描述】:

Elasticsearch 7.7,我正在使用官方的php客户端与服务器交互。

我的问题在这里得到了一些解决:https://discuss.elastic.co/t/need-to-return-part-of-a-doc-from-a-search-query-filter-is-parent-child-the-way-to-go/64514/2

但是“7.0+ 中的 API 已弃用类型” https://www.elastic.co/guide/en/elasticsearch/reference/7.x/removal-of-types.html

这是我的文件:

{
  "offering_id": "1190",
  "account_id": "362353",
  "service_id": "20087",
  "title": "Quick Brown Mammal",
  "slug": "Quick Brown Fox",
  "summary": "Quick Brown Fox"
  "header_thumb_path": "uploads/test/test.png",
  "duration": "30",
  "alter_ids": [
    "59151",
    "58796",
    "58613",
    "54286",
    "51812",
    "50052",
    "48387",
    "37927",
    "36685",
    "36554",
    "28807",
    "23154",
    "22356",
    "21480",
    "220",
    "1201",
    "1192"
  ],
  "premium": "f",
  "featured": "f",
  "events": [
    {
      "event_id": "9999",
      "start_date": "2020-07-01 14:00:00",
      "registration_count": "22",
      "description": "boo"
    },
    {
      "event_id": "9999",
      "start_date": "2020-07-01 14:00:00",
      "registration_count": "22",
      "description": "xyz"
    },
    {
      "event_id": "9999",
      "start_date": "2020-08-11 11:30:00",
      "registration_count": "41",
      "description": "test"
    }
  ]
}

注意对象可能有一个或多个“事件”

基于事件数据的搜索是最常见的用例。

例如:

  • 查找在中午 12 点之前开始的活动
  • 查找描述为“xyz”的事件
  • 列出开始日期在未来 10 天内的查找事件。

我不想返回任何与查询不匹配的事件!


所以,例如Find events with a description of "xyz" for a given service

{
  "query": {
    "bool": {
      "must": {
        "match": {
          "events.description": "xyz"
        }
      },
      "filter": {
        "bool": {
          "must": [
            {
              "term": {
                "service_id": 20087
              }
            }
          ]
        }
      }
    }
  }
}

我希望结果如下所示:

{
  "offering_id": "1190",
  "account_id": "362353",
  "service_id": "20087",
  "title": "Quick Brown Mammal",
  "slug": "Quick Brown Fox",
  "summary": "Quick Brown Fox"
  "header_thumb_path": "uploads/test/test.png",
  "duration": "30",
  "alter_ids": [
    "59151",
    "58796",
    "58613",
    "54286",
    "51812",
    "50052",
    "48387",
    "37927",
    "36685",
    "36554",
    "28807",
    "23154",
    "22356",
    "21480",
    "220",
    "1201",
    "1192"
  ],
  "premium": "f",
  "featured": "f",
  "events": [
    {
      "event_id": "9999",
      "start_date": "2020-07-01 14:00:00",
      "registration_count": "22",
      "description": "xyz"
    }
  ]
}

但是,它只是返回整个文档以及所有事件。

是否甚至可以只返回数据的子集?也许是聚合?

  • 现在,我们正在对应用程序(在本例中为 php)中的结果集进行“额外”过滤,以去除与所需结果不匹配的事件块。
  • 最好让弹性直接给出所需的内容,而不是对结果进行额外处理以提取适用的事件。
  • 考虑过重组数据,以使其基于“事件”,但随后我将复制数据,因为每个产品也将具有父数据。

这曾经是在 SQL 中,其中有一个关系,而不是像这样嵌套数据。

【问题讨论】:

  • 如果这是您的主要用例并且返回额外的嵌套文档是一个问题(从您的示例中不清楚 - 有一些额外的文档不是问题),那么您可以考虑展平文档 -在顶层存储事件字段并为每个事件生成一个 ES 文档。
  • 你能添加一个查询,它给你整个数据,而不是一个。
  • @Gibbs 我添加了一个搜索查询示例。这几乎是这个应用程序会做的“最简单”的搜索。我已经反向尝试过(匹配服务,然后过滤事件等),它们都只给了我整个对象。
  • @khachik 是的,我认为你是对的!不幸的是,未来的用例将是大量数据,不嵌套它会真正增加基础设施成本。对于这个特定的“事件”场景,我认为这就是我们要做的,但我必须有能力为弹性搜索中的未来用例有效地处理嵌套数据,所以我真的很想知道只撤回某些嵌套对象的策略,比如6.x 及以下版本。

标签: elasticsearch elasticsearch-aggregation elasticsearch-dsl


【解决方案1】:

可以使用嵌套聚合和过滤聚合返回嵌套数据的子集

要了解有关这些聚合的更多信息,请参阅以下官方文档:

Filter Aggregation

Nested Aggregation

索引映射:

{
  "mappings": {
    "properties": {
      "offering_id": {
        "type": "integer"
      },
      "account_id": {
        "type": "integer"
      },
      "service_id": {
        "type": "integer"
      },
      "title": {
        "type": "text"
      },
      "slug": {
        "type": "text"
      },
      "summary": {
        "type": "text"
      },
      "header_thumb_path": {
        "type": "keyword"
      },
      "duration": {
        "type": "integer"
      },
      "alter_ids": {
        "type": "integer"
      },
      "premium": {
        "type": "text"
      },
      "featured": {
        "type": "text"
      },
      "events": {
        "type": "nested",
        "properties": {
          "event_id": {
            "type": "integer"
          },
          "registration_count": {
            "type": "integer"
          },
          "description": {
            "type": "text"
          }
        }
      }
    }
  }
}

搜索查询:

{
  "size": 0,
  "aggs": {
    "nested": {
      "nested": {
        "path": "events"
      },
      "aggs": {
        "filter": {
          "filter": {
            "match": { "events.description": "xyz" }
          },
          "aggs": {
            "total": {
              "top_hits": {
                "size": 10
              }
            }
          }
        }
      }
    }
  }
}

搜索结果:

"hits": [
          {
            "_index": "foo21",
            "_type": "_doc",
            "_id": "1",
            "_nested": {
              "field": "events",
              "offset": 1
            },
            "_score": 1.0,
            "_source": {
              "event_id": "9999",
              "start_date": "2020-07-01 14:00:00",
              "registration_count": "22",
              "description": "xyz"
            }
          }
        ]

第二种方法:

{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "service_id": "20087"
          }
        },
        {
          "nested": {
            "path": "events",
            "query": {
              "bool": {
                "must": [
                  {
                    "match": {
                      "events.description": "xyz"
                    }
                  }
                ]
              }
            },
            "inner_hits": {
              
            }
          }
        }
      ]
    }
  }
}

你甚至可以通过这个 SO 答案:

How to filter nested aggregation bucket?

Returning a partial nested document in ElasticSearch

【讨论】:

猜你喜欢
  • 2015-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多