You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Elasticsearch聚合查询中消除重复文档

嘿,针对你遇到的Elasticsearch聚合时要消除topics数组重复的文档这个问题,我给你两个实用的解决方案,看哪种更适合你的场景:

方法1:聚合时通过脚本动态生成唯一键(无需修改原始数据)

如果不想改动现有索引结构,你可以直接在聚合里用脚本把topics数组转换成一个唯一的字符串,这样内容完全相同的数组会被归为同一个聚合桶,自然就实现了去重。

针对数组顺序一致的重复(比如["Health","Fitness"]只和完全同顺序的数组算重复)

用这个DSL查询:

GET /testindex/_search
{
  "size": 0, // 不返回原始文档,只看聚合结果
  "aggs": {
    "unique_topics_groups": {
      "terms": {
        "script": {
          "source": "doc['topics'].value.join(',')" // 把数组用逗号拼接成字符串
        },
        "size": 100 // 根据你的实际数据量调整桶的数量
      },
      "aggs": {
        "sample_doc": {
          "top_hits": {
            "size": 1 // 每个去重后的组返回一个示例文档,方便查看
          }
        }
      }
    }
  }
}

忽略数组顺序的重复(比如["Health","Fitness"]和["Fitness","Health"]算重复)

如果需要不管数组元素的顺序,只要内容相同就算重复,可以修改脚本先排序再拼接:

GET /testindex/_search
{
  "size": 0,
  "aggs": {
    "unique_topics_groups": {
      "terms": {
        "script": {
          "source": "doc['topics'].value.stream().sorted().collect(Collectors.joining(','))"
        },
        "size": 100
      },
      "aggs": {
        "sample_doc": {
          "top_hits": {
            "size": 1
          }
        }
      }
    }
  }
}
方法2:提前生成衍生字段(适合大数据量场景,性能更优)

如果你的索引数据量很大,脚本聚合可能会有性能开销,这时候建议提前给每个文档生成一个存储topics数组唯一标识的字段,聚合时直接用这个字段,速度会快很多。

步骤1:添加衍生字段的映射

先给索引新增一个topics_unique_key字段(类型为keyword,适合聚合):

PUT /testindex/_mapping
{
  "properties": {
    "topics": {
      "type": "keyword"
    },
    "topics_unique_key": {
      "type": "keyword"
    }
  }
}

步骤2:批量更新现有文档的衍生字段

_update_by_query给所有文档生成这个字段(同样可以选择是否排序):

// 不考虑顺序的版本
POST /testindex/_update_by_query
{
  "script": {
    "source": "ctx._source.topics_unique_key = ctx._source.topics.stream().sorted().collect(Collectors.joining('|'))"
  }
}

// 考虑顺序的版本
POST /testindex/_update_by_query
{
  "script": {
    "source": "ctx._source.topics_unique_key = ctx._source.topics.join('|')"
  }
}

这里我用了|作为分隔符,避免和数组元素里可能存在的逗号冲突,你可以换成其他不常用的字符。

步骤3:用衍生字段做聚合

现在直接用topics_unique_key字段做terms聚合,性能拉满:

GET /testindex/_search
{
  "size": 0,
  "aggs": {
    "unique_topics_groups": {
      "terms": {
        "field": "topics_unique_key",
        "size": 100
      },
      "aggs": {
        "sample_doc": {
          "top_hits": {
            "size": 1
          }
        }
      }
    }
  }
}

额外提示

如果是新写入的文档,你可以用Ingest Pipeline自动生成topics_unique_key字段,这样就不用每次手动更新了。

内容的提问来源于stack exchange,提问作者user8590996

火山引擎 最新活动