Elasticsearch 流水线搜索?
Elasticsearch Pipelined search?
我在公司使用 Elasticsearch 有一段时间了,到目前为止,我们的搜索似乎运行良好。
我们已经看到来自客户的更复杂的用例需要更多 "ad-hoc/advanced" 查询功能和文档间关系(或传统意义上的连接)。
我知道 ES 不是为连接而构建的,非规范化是推荐的方式。到目前为止,我们一直在对文档进行非规范化以支持每个用例,而这本身对我们来说已经变得过于复杂和昂贵,因为我们的客户必须等待很长时间才能推出此代码更改。
我们比 "Hey your data model isn't right. It isn't suited for smarter queries" 更经常受到业务的批评。团队每次都很难让他们理解为什么需要非规范化。
问题的几个例子:
"Find me all the persons having the same birthdays"
"Find me all the persons travelling to the same cities within the same time frame"
想象一下,每个事件文档都是一个包含旅行详细信息的个人记录。
那么是否有管道搜索的概念,我可以将搜索分解为多个搜索查询并将一个搜索查询的输出作为输入传递给另一个搜索查询?
或者有没有其他推荐的方法可以解决这些类型的问题而不必煮沸海洋?
以上两个查询都可以通过聚合来解决。
我假设以下示例 document/schema:
{
"firstName": "John",
"lastName": "Doe",
"birthDate": "1998-04-02",
"travelDate": "2019-10-31",
"city": "London"
}
第一个通过在生日字段(一年中的第几天)和 min_doc_count: 2
上聚合 terms
,例如:
{
"size": 0,
"aggs": {
"birthdays": {
"terms": {
"script": "return LocalDate.parse(params._source.birthDate).format(DateTimeFormatter.ofPattern('MM/dd'))",
"min_doc_count": 2
},
"aggs": {
"persons": {
"top_hits": {}
}
}
}
}
}
第二个通过在 city
字段上使用 terms
聚合进行聚合,并在 travelDate
字段上使用 range
查询对所需时间范围进行约束:
{
"size": 0,
"query": {
"range": {
"travelDate": {
"gte": "2019-10-01",
"lt": "2019-11-01"
}
}
},
"aggs": {
"cities": {
"terms": {
"field": "city.keyword"
},
"aggs": {
"persons": {
"top_hits": {}
}
}
}
}
}
第二个查询也可以用field collapsing:
{
"_source": false,
"query": {
"range": {
"travelDate": {
"gte": "2019-10-01",
"lt": "2019-11-01"
}
}
},
"collapse": {
"field": "city.keyword",
"inner_hits": {
"name": "people"
}
}
}
如果你同时需要这两个聚合,绝对可以这样做:
{
"size": 0,
"aggs": {
"birthdays": {
"terms": {
"script": "return LocalDate.parse(params._source.birthDate).format(DateTimeFormatter.ofPattern('MM/dd'))",
"min_doc_count": 2
},
"aggs": {
"persons": {
"top_hits": {}
}
}
},
"travels": {
"filter": {
"range": {
"travelDate": {
"gte": "2019-10-01",
"lt": "2019-11-01"
}
}
},
"aggs": {
"cities": {
"terms": {
"field": "city.keyword"
},
"aggs": {
"persons": {
"top_hits": {}
}
}
}
}
}
}
}
我在公司使用 Elasticsearch 有一段时间了,到目前为止,我们的搜索似乎运行良好。 我们已经看到来自客户的更复杂的用例需要更多 "ad-hoc/advanced" 查询功能和文档间关系(或传统意义上的连接)。 我知道 ES 不是为连接而构建的,非规范化是推荐的方式。到目前为止,我们一直在对文档进行非规范化以支持每个用例,而这本身对我们来说已经变得过于复杂和昂贵,因为我们的客户必须等待很长时间才能推出此代码更改。
我们比 "Hey your data model isn't right. It isn't suited for smarter queries" 更经常受到业务的批评。团队每次都很难让他们理解为什么需要非规范化。
问题的几个例子:
"Find me all the persons having the same birthdays"
"Find me all the persons travelling to the same cities within the same time frame"
想象一下,每个事件文档都是一个包含旅行详细信息的个人记录。
那么是否有管道搜索的概念,我可以将搜索分解为多个搜索查询并将一个搜索查询的输出作为输入传递给另一个搜索查询? 或者有没有其他推荐的方法可以解决这些类型的问题而不必煮沸海洋?
以上两个查询都可以通过聚合来解决。
我假设以下示例 document/schema:
{
"firstName": "John",
"lastName": "Doe",
"birthDate": "1998-04-02",
"travelDate": "2019-10-31",
"city": "London"
}
第一个通过在生日字段(一年中的第几天)和 min_doc_count: 2
上聚合 terms
,例如:
{
"size": 0,
"aggs": {
"birthdays": {
"terms": {
"script": "return LocalDate.parse(params._source.birthDate).format(DateTimeFormatter.ofPattern('MM/dd'))",
"min_doc_count": 2
},
"aggs": {
"persons": {
"top_hits": {}
}
}
}
}
}
第二个通过在 city
字段上使用 terms
聚合进行聚合,并在 travelDate
字段上使用 range
查询对所需时间范围进行约束:
{
"size": 0,
"query": {
"range": {
"travelDate": {
"gte": "2019-10-01",
"lt": "2019-11-01"
}
}
},
"aggs": {
"cities": {
"terms": {
"field": "city.keyword"
},
"aggs": {
"persons": {
"top_hits": {}
}
}
}
}
}
第二个查询也可以用field collapsing:
{
"_source": false,
"query": {
"range": {
"travelDate": {
"gte": "2019-10-01",
"lt": "2019-11-01"
}
}
},
"collapse": {
"field": "city.keyword",
"inner_hits": {
"name": "people"
}
}
}
如果你同时需要这两个聚合,绝对可以这样做:
{
"size": 0,
"aggs": {
"birthdays": {
"terms": {
"script": "return LocalDate.parse(params._source.birthDate).format(DateTimeFormatter.ofPattern('MM/dd'))",
"min_doc_count": 2
},
"aggs": {
"persons": {
"top_hits": {}
}
}
},
"travels": {
"filter": {
"range": {
"travelDate": {
"gte": "2019-10-01",
"lt": "2019-11-01"
}
}
},
"aggs": {
"cities": {
"terms": {
"field": "city.keyword"
},
"aggs": {
"persons": {
"top_hits": {}
}
}
}
}
}
}
}