elasticsearch中如何实现dinstinct去重功能

本文介绍在Elasticsearch中实现数据去重的方法,包括SQL查询和聚合查询两种方式,并解决ES查询中的一些常见问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、功能场景

在mysql数据库中查询数据时,我们可以采用dinstinct关键字去重。那么,在ES中如何实现查询结果去重呢?


二、原理分析

DISTINCT关键字去重的sql语句等价于对需要去重的字段进行GROUP BY。

以下2个sql都能实现对name,age字段查询结果的去重。

SELECT DISTINCT name,age FROM distinct_index

SELECT name,age FROM distinct_index GROUP BY name,age

三、方案汇总

根据上面的分析,总结出以下2种实现方案:
1、使用GROUP BY的SQL查询
2、使用Aggregation(聚合)查询
说明:
ES6.3之后的版本以及支持SQL查询

四、数据准备

## 删除索引
## DELETE distinct_index
## 新建索引
PUT distinct_index
{
  "mappings": {
    "properties": {
      "name": {
        "type": "keyword"
      },
      "age": {
        "type": "integer"
      }
    }
  }
}
## 添加数据
POST distinct_index/_bulk?refresh
{ "create": { } }
{ "name": "小天", "age": 25}
{ "create": { } }
{ "name": "小天", "age": 25}
{ "create": { } }
{ "name": "老万", "age": 35}
{ "create": { } }
{ "name": "老王", "age": 45}
{ "create": { } }
{ "name": "小明", "age": 15}
{ "create": { } }
{ "name": "小明", "age": 15}
{ "create": { } }
{ "name": "小红", "age": 12}
{ "create": { } }
{ "name": "乐乐", "age": 18}

五、方案实战

1、SQL查询方案

##可以通过format参数控制返回结果的格式,txt表示文本格式,看起来更直观点,默认为json格式。
POST _sql?format=txt
{
  "query": "SELECT name,age FROM distinct_index group by name,age"
}

查询结果:
在这里插入图片描述
和预期相符,查询结果达到去重的效果。

SQL语句转DSL:

POST /_sql/translate
{
  "query": "SELECT name,age FROM distinct_index group by name,age"
}

结果:

{
  "size" : 0,
  "_source" : false,
  "stored_fields" : "_none_",
  "aggregations" : {
    "groupby" : {
      "composite" : {
        "size" : 1000,
        "sources" : [
          {
            "f5b401c4" : {
              "terms" : {
                "field" : "name",
                "missing_bucket" : true,
                "order" : "asc"
              }
            }
          },
          {
            "f557e07b" : {
              "terms" : {
                "field" : "age",
                "missing_bucket" : true,
                "order" : "asc"
              }
            }
          }
        ]
      }
    }
  }
}

说明:
通过将sql语句转为dsl语句可以发现,sql语句中的group by查询底层原理是转化成了dsl中的aggregations聚合查询。

2、aggregations聚合查询

POST distinct_index/_search
{
	"from": 0,
	"size": 0,
	"aggregations": {
		"name": {
			"terms": {
				"field": "name",
				"size": 2147483647
			},
			"aggregations": {
				"age": {
					"terms": {
						"field": "age",
						"size": 2147483647
					}
				}
			}
		}
	}
}

查询结果:

{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 8,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "name" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "小天",
          "doc_count" : 2,
          "age" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : 25,
                "doc_count" : 2
              }
            ]
          }
        },
        {
          "key" : "小明",
          "doc_count" : 2,
          "age" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : 15,
                "doc_count" : 2
              }
            ]
          }
        },
        {
          "key" : "乐乐",
          "doc_count" : 1,
          "age" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : 18,
                "doc_count" : 1
              }
            ]
          }
        },
        {
          "key" : "小红",
          "doc_count" : 1,
          "age" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : 12,
                "doc_count" : 1
              }
            ]
          }
        },
        {
          "key" : "老万",
          "doc_count" : 1,
          "age" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : 35,
                "doc_count" : 1
              }
            ]
          }
        },
        {
          "key" : "老王",
          "doc_count" : 1,
          "age" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : 45,
                "doc_count" : 1
              }
            ]
          }
        }
      ]
    }
  }
}

六、异常记录

1、ES中的sql查询不支持DISTINCT关键字

POST _sql?format=txt
{
  "query": "SELECT DISTINCT name,age FROM distinct_index"
}

报错:

{
  "error" : {
    "root_cause" : [
      {
        "type" : "verification_exception",
        "reason" : "Found 1 problem\nline 1:8: SELECT DISTINCT is not yet supported"
      }
    ],
    "type" : "verification_exception",
    "reason" : "Found 1 problem\nline 1:8: SELECT DISTINCT is not yet supported"
  },
  "status" : 400
}

2、ES的sql查询中表名中不能有中划线,比如my-index-000001

PUT my-index-000001
{
  "mappings": {
    "properties": {
      "name": {
        "type": "keyword"
      },
      "age": {
        "type": "integer"
      }
    }
  }
}

POST _sql?format=txt
{
  "query": "SELECT name FROM my-index-000001"
}

报错:

{
  "error" : {
    "root_cause" : [
      {
        "type" : "parsing_exception",
        "reason" : "line 1:20: extraneous input '-' expecting {<EOF>, ',', 'ANALYZE', 'ANALYZED', 'AS', 'CATALOGS', 
        ……

遇到这种情况,最简单方法是给索引添加别名。

POST /_aliases
{
  "actions" : [
    { "add" : { "index" : "my-index-000001", "alias" : "my_index" } }
  ]
}
POST _sql?format=txt
{
  "query": "SELECT name FROM my_index"
}

总结

本文主要介绍了ES中如何实现类似dinstinct的数据去重功能。
1、首先通过通过dinstinct和group by的等价sql语句,说明可以通过分组函数实现数据去重。
2、分别介绍了ES中通过sql语句查询和aggregations聚合查询实现对查询结果的去重。
3、ES中的sql查询不支持DISTINCT关键字
4、ES中的sql查询中表名不能包含中划线,比如my-index-000001

### 回答1: 在Elasticsearch6中,可以使用terms聚合实现操作。下面是一个Java示例代码: ```java SearchRequest searchRequest = new SearchRequest("your_index"); // 指定索引名称 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.size(0); // 只需要聚合结果,不需要返回文档 TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("duplicate_count").field("your_field"); // 指定需要的字段 searchSourceBuilder.aggregation(aggregationBuilder); searchRequest.source(searchSourceBuilder); SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); Terms terms = searchResponse.getAggregations().get("duplicate_count"); List<? extends Terms.Bucket> buckets = terms.getBuckets(); for (Terms.Bucket bucket : buckets) { String key = bucket.getKeyAsString(); // 后的值 long docCount = bucket.getDocCount(); // 该值出现的文档数量 // TODO: 处理聚合结果 } ``` 其中,`your_index`为需要进行操作的索引名称,`your_field`为需要的字段名称,可以根据实际情况进行修改。在处理聚合结果时,可以根据需要进行进一步的处理。 ### 回答2: 在使用Java操作Elasticsearch6实现操作时,我们可以通过以下步骤实现: 1. 创建Elasticsearch的连接和初始化客户端。 例如,我们可以使用以下代码创建和初始化客户端: ```java RestHighLevelClient client = new RestHighLevelClient( RestClient.builder(new HttpHost("localhost", 9200, "http"))); ``` 2. 使用Elasticsearch的搜索API进行操作。 可以使用Elasticsearch的搜索API来查询需要的字段,并通过聚合操作筛选出唯一的值。具体步骤如下: ```java // 创建一个SearchRequest对象 SearchRequest searchRequest = new SearchRequest("your_index_name"); // 创建一个SearchSourceBuilder对象,并设置聚合操作 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); sourceBuilder.aggregation(AggregationBuilders .terms("unique_values").field("your_field_name").size(10000)); // 将SearchSourceBuilder对象设置到SearchRequest中 searchRequest.source(sourceBuilder); // 执行搜索操作 SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT); // 从响应中获取聚合结果 Terms agg = response.getAggregations().get("unique_values"); // 遍历聚合结果并输出唯一值 for (Terms.Bucket bucket : agg.getBuckets()) { System.out.println("Unique value: " + bucket.getKeyAsString()); } ``` 在上述代码中,我们创建了一个SearchRequest对象,并指定了需要进行的字段。然后,我们创建了一个SearchSourceBuilder对象,并使用aggregation方法设置了聚合操作。最后,我们执行搜索操作并从响应中获取聚合结果。 以上就是使用Java操作Elasticsearch6实现操作的简要步骤。根据具体需求,我们可以通过调整代码来实现更复杂的逻辑。 ### 回答3: Java操作Elasticsearch6实现操作主要依赖于Elasticsearch Java High Level REST Client,以下是一个简单实现的步骤: 1. 首先,我们需要创建一个Elasticsearch的客户端连接: ```java RestHighLevelClient client = new RestHighLevelClient( RestClient.builder(new HttpHost("localhost", 9200, "http"))); ``` 2. 接下来,我们可以使用Search API来实现操作。首先,我们需要创建一个SearchRequest对象并设置索引名称和搜索条件: ```java SearchRequest searchRequest = new SearchRequest("index_name"); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.matchAllQuery()); // 设置查询条件 searchSourceBuilder.aggregation(AggregationBuilders .terms("deduplication") .field("field_name") .size(10000)); // 设置字段和聚合大小 searchRequest.source(searchSourceBuilder); ``` 3. 然后,我们可以发送搜索请求来获得后的结果: ```java SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); Terms aggregation = searchResponse.getAggregations().get("deduplication"); for (Terms.Bucket bucket : aggregation.getBuckets()) { String fieldValue = bucket.getKey().toString(); System.out.println("Deduplicated Field Value: " + fieldValue); } ``` 在上述代码中,我们通过聚合操作(aggregation)中的terms功能实现。使用聚合将结果按照指定字段(field_name)分组,然后获取每个分组的聚合结果(deduplication)。 以上是使用Java操作Elasticsearch6实现操作的简单示例。请注意,具体的实现可能根据实际需求有所调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

斗者_2013

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值