在大多数搜索应用程序中,尤其是在电商、社交媒体或内容聚合平台中,我们常常遇到这样一个需求:希望将具有相同属性(例如同一商品的不同规格、同一作者的不同文章等)的搜索结果合并或折叠在一起,而不是显示冗余的重复项。Elasticsearch 提供了一个强大的功能来实现这一需求:Field Collapsing。本文将详细介绍 Elasticsearch 的 Field Collapsing 功能及其使用场景。
什么是 Field Collapsing?
Field Collapsing 是 Elasticsearch 7.x 版本开始引入的一个特性,它允许你将搜索结果按照某个字段的值进行折叠。折叠的结果中,每个唯一字段值只会显示一个文档,而不是展示所有匹配的文档。这在需要去重、分组展示或提高结果精简度时非常有用。
典型应用场景
-
商品搜索:在电商平台上,同一商品可能有多个规格或颜色。如果不做折叠,用户在搜索时可能会看到多个几乎相同的结果。使用 Field Collapsing,可以只展示每个商品的一个结果,而不是多个规格版本。
-
内容聚合:在新闻或社交媒体平台中,同一作者可能发布多篇相似内容。折叠可以确保每个作者只展示一个结果,而不是所有文章。
-
数据去重:对于某些场景,特别是去重场景,Field Collapsing 可以直接根据指定字段折叠相同的文档,减少重复结果。
Field Collapsing 的工作原理
Field Collapsing 的核心在于通过一个字段来对结果集进行分组和折叠。在 Elasticsearch 的查询中,可以通过 collapse
参数实现这一功能。该参数通常配合 inner_hits
来展示每个折叠组中的具体文档信息。
基本用法
我们来看看如何在 Elasticsearch 查询中使用 Field Collapsing。
示例场景:商品搜索
假设我们有一个商品索引,其中包含多个规格的同一商品。我们希望在用户搜索时,只展示每个商品的一个版本,而不是显示所有规格。
索引示例
POST /products/_bulk
{ "index": { "_id": "1" } }
{ "name": "iPhone 12", "color": "black", "price": 699 }
{ "index": { "_id": "2" } }
{ "name": "iPhone 12", "color": "white", "price": 699 }
{ "index": { "_id": "3" } }
{ "name": "iPhone 12", "color": "red", "price": 699 }
{ "index": { "_id": "4" } }
{ "name": "Samsung Galaxy S21", "color": "black", "price": 799 }
{ "index": { "_id": "5" } }
{ "name": "Samsung Galaxy S21", "color": "white", "price": 799 }
查询示例
为了折叠具有相同商品名称的结果,我们可以使用如下的查询:
GET /products/_search
{
"query": {
"match_all": {}
},
"collapse": {
"field": "name.keyword"
}
}
结果解释
上述查询中,collapse
参数指定了 name.keyword
字段。查询结果会根据该字段的唯一值进行折叠,每个唯一值只会返回一个文档。这意味着,对于 iPhone 12
,无论有多少个颜色规格,只会返回一个结果。
{
"hits": {
"hits": [
{
"_id": "1",
"_source": {
"name": "iPhone 12",
"color": "black",
"price": 699
}
},
{
"_id": "4",
"_source": {
"name": "Samsung Galaxy S21",
"color": "black",
"price": 799
}
}
]
}
}
在这个结果中,我们只看到了每个产品系列中的一个条目,而不是所有规格。
使用 Inner Hits 查看折叠组中的其他文档
有时候,我们不仅仅希望看到折叠后的结果,还想查看每个折叠组中其他的文档。Elasticsearch 提供了 inner_hits
参数来满足这一需求。
示例查询
GET /products/_search
{
"query": {
"match_all": {}
},
"collapse": {
"field": "name.keyword",
"inner_hits": {
"name": "related_variants",
"size": 3
}
}
}
结果解释
在上述查询中,inner_hits
参数让我们能够查看每个折叠组中的其他文档。结果中,除了主文档外,还会包含一个 inner_hits
字段,展示该组内的其他文档。
{
"hits": {
"hits": [
{
"_id": "1",
"_source": {
"name": "iPhone 12",
"color": "black",
"price": 699
},
"inner_hits": {
"related_variants": {
"hits": {
"hits": [
{
"_id": "2",
"_source": {
"name": "iPhone 12",
"color": "white",
"price": 699
}
},
{
"_id": "3",
"_source": {
"name": "iPhone 12",
"color": "red",
"price": 699
}
}
]
}
}
}
},
{
"_id": "4",
"_source": {
"name": "Samsung Galaxy S21",
"color": "black",
"price": 799
},
"inner_hits": {
"related_variants": {
"hits": {
"hits": [
{
"_id": "5",
"_source": {
"name": "Samsung Galaxy S21",
"color": "white",
"price": 799
}
}
]
}
}
}
}
]
}
}
在这里,你可以看到 iPhone 12
的主结果(黑色款)和相关的其他两个颜色(白色和红色)。
Field Collapsing 的限制
-
不能与聚合一起使用:Field Collapsing 不能与某些聚合查询(如
terms
聚合)直接配合使用。这是因为聚合是在全局范围内执行的,而 Field Collapsing 仅对返回的结果集生效。 -
不适合深度分页:当进行深度分页时,Field Collapsing 的性能会下降。对于需要深度分页的场景,可以考虑使用滚动分页(scroll)或其他优化方案。
-
无法在分片之间折叠:Field Collapsing 是在单个分片内完成的。这意味着同一字段值可能出现在不同的分片中,导致未完全折叠的情况。
总结
Elasticsearch 的 Field Collapsing 是一个强大而实用的功能,尤其适用于需要将重复或相似的结果折叠在一起的场景。通过简单的配置,你可以显著提高搜索结果的简洁度和用户体验。同时,借助 inner_hits
参数,你还可以灵活地展示折叠组中的其他相关文档。
在使用 Field Collapsing 时,需要考虑其与聚合查询的兼容性以及深度分页的性能影响。在合适的场景下,Field Collapsing 可以帮助你构建更高效、更友好的搜索应用。
希望本文能帮助你更好地理解和使用 Elasticsearch 的 Field Collapsing 功能。如果你在实际项目中有更多的需求或疑问,欢迎进一步探讨与交流。