码到三十五 : 个人主页
一 、collapse折叠去重
elasticsearch中的collapse功能答应用户对搜索结果进行分组,这在某些环境下可以看作是一种去重利用。它的主要目的是在搜索大量文档时,只表现每个分组的一个代表文档,而不是表现全部匹配的文档。
原理
collapse功能基于一个或多个字段的值对搜索结果进行分组。当你指定了collapse参数后,Elasticsearch会在后台对匹配的文档进行分组,并且每个分组只会返回一个代表文档。这个代表文档通常是分组中的第一个文档,但也可以通过其他参数进行定制。
用法
以下是怎样在Elasticsearch查询中使用collapse的基本示例:
- {
- "query": {
- "match": {
- "field": "value"
- }
- },
- "collapse": {
- "field": "group_field"
- }
- }
复制代码 在这个示例中:
- query部分定义了搜索的基本条件。在这个例子中,我们搜索字段field值为value的文档。
- collapse部分指定了用于分组的字段,即group_field。全部在这个字段上具有相同值的文档将被分组在一起,并且只返回一个代表文档。
你还可以通过添加inner_hits参数来定制返回的分组代表文档。比方,假如你想在每个分组中返回评分最高的文档,你可以这样做:
- {
- "query": {
- "match": {
- "field": "value"
- }
- },
- "collapse": {
- "field": "group_field",
- "inner_hits": {
- "name": "most_relevant",
- "size": 1,
- "sort": [
- {
- "_score": {
- "order": "desc"
- }
- }
- ]
- }
- }
- }
复制代码
- inner_hits部分定义了如作甚每个分组选择代表文档。这里,我们定名了inner_hits的结果为most_relevant。
- size: 1表示每个分组只返回一个文档。
- sort部分指定了怎样对分组内的文档进行排序。在这里,我们根据文档的评分(_score)进行降序排序,因此每个分组的代表文档将是该分组中评分最高的文档。
注意事项
- 性能开销:在大数据集上应用collapse功能大概会带来额外的性能开销,因为需要对结果进行分组和排序利用。
- 分页复杂性:当与分页功能结合使用时,需要注意Elasticsearch的分页是基于索引序次,而不是折叠后的序次,这大概导致深度分页时的性能题目或结果不一致。
- 不能与scroll、rescore及search_after结合使用: 由于collapse需要对结果进行分组和排序以确定每个组的最佳匹配文档,这个过程大概会与scroll、rescore和search_after的某些功能冲突。
- 性能表现:虽然collapse通常比完全的分组和聚合利用更高效,因为它只返回每个组的最佳文档,但处置惩罚大量数据时仍大概产生性能开销。
- 字段范例:collapse参数所使用的字段必须是keyword或number范例,因为这些范例的字段值精确,实用于分组和排序。使用text范例字段大概导致不准确的结果。
在使用collapse时,请务必思量这些限定和注意事项,以确保查询的准确性和性能。通过合理规划和优化查询,可以充分利用collapse的分组功能,同时克制潜在的性能瓶颈。
二、字段聚合(terms) + top_hits聚合 去重
结合使用字段聚合(terms)和top_hits聚合可以实现去重功能。
原理
- 字段聚合(terms):此聚合范例用于表现某个字段中的唯一值及其对应的文档数目。通过字段聚合,我们可以将数据按照指定字段的不同值进行分组。
- top_hits聚合:此聚合范例用于在每个分组(bucket)内部返回最匹配的文档。当与terms聚合结合使用时,它可以在每个分组中返回指定数目的文档,通常用于返回每个分组的代表性文档。
结合这两种聚合,我们可以先按照某个字段进行分组(实现初步的“去重”效果,即每个分组代表一个唯一的字段值),然后在每个分组中使用top_hits聚合返回代表性的文档,从而实现更精致的去重功能。
用法
- 构建基础查询:首先,你需要构建一个基础的Elasticsearch查询,用于筛选出需要进行去重处置惩罚的文档聚集。
- 添加terms聚合:在查询的聚合部分,添加一个terms聚合,并指定需要按其进行分组的字段。这样,Elasticsearch会将全部文档按照该字段的唯一值进行分组。
- 嵌套top_hits聚合:在terms聚合的每个分组中,嵌套一个top_hits聚合。这样,在每个分组内部,你可以指定返回最匹配的文档数目(通常是1,以实现去重效果)。
- (可选)定制top_hits:你可以进一步定制top_hits聚合,比方通过指定排序方式来控制返回的代表性文档。
有一个包罗商品信息的索引,并且你想按照“品牌”字段对商品进行去重,以便每个品牌只表现一个代表性商品。查询大概如下所示:
- GET /products/_search
- {
- "size": 0, // 不返回具体的匹配文档,只返回聚合结果
- "aggs": {
- "brands": { // terms聚合,按品牌分组
- "terms": {
- "field": "brand",
- "size": 10 // 假设我们想要获取前10个品牌的商品
- },
- "aggs": {
- "top_product": { // 在每个品牌分组内,使用top_hits聚合返回代表性商品
- "top_hits": {
- "size": 1, // 每个品牌只返回一个代表性商品
- "sort": [ // 可以根据需要指定排序方式,例如按评分或价格排序
- {
- "_score": { // 按评分排序
- "order": "desc"
- }
- }
- ]
- }
- }
- }
- }
- }
- }
复制代码 我们首先使用terms聚合按照“品牌”字段对商品进行分组,然后在每个分组中使用top_hits聚合返回一个代表性商品(评分最高的商品)。这样,我们就实现了按照品牌对商品进行去重的功能。
三、两种方法的比较
字段聚合(terms)+ top_hits聚合
- 原理:这种方法首先使用terms聚合按某个字段的值进行分组,然后在每个分组内部使用top_hits聚合来获取每个分组的顶部文档。
- 灵活性:非常高。你可以自定义terms聚合的字段,以及top_hits聚合返回的文档数目和排序方式。
- 性能:依赖于聚合字段的基数(即不同值的数目)。假如基数很大,性能大概会受到影响,因为需要为每个不同的值进行聚合。
- 结果:返回的是每个分组的一个或多个代表文档,以及每个分组的巨细等信息。
- 用途:实用于需要对数据进行多维分析和统计的场景。
使用collapse功能
- 原理:collapse功能通过指定一个字段来对搜索结果进行分组,并且每组只返回一个最佳匹配的文档(通常是基于排序字段的最高或最低值)。
- 灵活性:相对较低。你只能基于一个字段进行分组,并且每组只返回一个文档。
- 性能:通常比字段聚合更高效,因为它不需要盘算每个分组的统计信息,只需要找到每个分组的最佳匹配文档。
- 结果:返回的是每个分组的最佳匹配文档。
- 用途:实用于只需要获取每个分组的代表文档,而不需要详细统计信息的场景。
对比总结
- 灵活性:字段聚合+top_hits提供了更多的自定义选项,可以按多个字段进行分组,并控制返回的文档数目和排序。而collapse则更简朴直接,只基于一个字段进行分组。
- 性能:对于大数据集,collapse大概更高效,因为它克制了复杂的聚合盘算。然而,实际性能还取决于具体的使用场景和数据分布。
- 结果丰富性:字段聚合+top_hits可以返回更丰富的信息,包括分组巨细和多个代表文档。而collapse只返回每个分组的最佳文档。
在选择使用哪种方法时,应根据具体需求、数据量和性能要求来权衡。假如你需要详细的分组统计信息和多个代表文档,字段聚合+top_hits大概是更好的选择。假如你只需要快速获取每个分组的最佳文档,并且关注性能,那么collapse大概更适合你。
四、cardinality 统计去重后的数目
cardinality聚合是一种用于统计某个字段中不同值的数目基数(即去重后的数目)的功能。
原理
- 基于HyperLogLog++算法:cardinality聚合是基于HyperLogLog++(HLL)算法的近似算法。HLL会先对输入作哈希运算,然后根据哈希运算的结果中的bits做概率估算,从而得到基数值,即不同值的数目。
- 近似结果:需要注意的是,由于使用了HLL算法,cardinality聚合提供的是一个近似结果,而不是精确值。但在大多数环境下,这个近似值已经足够准确,可以满足业务需求。
- 性能优化:为了提拔性能,Elasticsearch在处置惩罚大数据集时会使用一定的优化策略,比如使用分桶和并行处置惩罚等技能来加速盘算过程。
用法
- 基础用法:要使用cardinality聚合,你需要在Elasticsearch的查询请求中指定一个cardinality聚合,并设置要统计的字段。比方,假如你想统计一个索引中“color”字段的不同值的数目,你可以发送一个包罗cardinality聚合的查询请求。
- 嵌套在其他聚合中:cardinality聚合还可以嵌套在其他聚合中,比如date_histogram聚合。这样,你可以按时间间隔(如每月、每天等)来统计不同值的数目。这对于分析时间序列数据中的唯一值数目非常有用。
- 调解精度:虽然cardinality聚合提供的是近似结果,但你可以通过调解相关参数来权衡精度和性能。Elasticsearch答应你设置精度阈值,以便在可接受的误差范围内获得更快的盘算结果。
假设你有一个包罗商品销售数据的Elasticsearch索引,你想统计“color”字段中有多少种不同的颜色。你可以使用以下查询来实现:
- GET /sales/_search
- {
- "query": {
- "range": {
- "date": {
- "gte": "2024-01-01",
- "lte": "2024-06-30"
- }
- }
- },
- "size": 0,
- "aggs": {
- "distinct_colors_in_period": {
- "cardinality": {
- "field": "color" ,
- "precision_threshold": 1000
- }
- }
- }
- }
复制代码 这个查询会返回一个聚合结果,其中包罗“color”字段中不同颜色的数目。
precision_threshold 参数阐明
cardinality 度量是一个近似算法。 它是基于 HyperLogLog++ (HLL)算法的。 HLL 会先对我们的输入作哈希运算,然后根据哈希运算的结果中的 bits 做概率估算从而得到基数。
我们不需要理解技能细节, 但我们最好应该关注一下这个算法的 特性 :
- 可设置的精度,用来控制内存的使用(更精确 = 更多内存)。
- 小的数据集精度黑白常高的。
- 我们可以通过设置参数,来设置去重需要的固定内存使用量。无论数千照旧数十亿的唯一值,内存使用量只与你设置的精确度相关。
要设置精度,我们必须指定 precision_threshold 参数的值。 这个阈值定义了在何种基数程度下我们盼望得到一个近乎精确的结果.
- recision_threshold 接受 0–40,000 之间的数字,更大的值照旧会被当作 40,000 来处置惩罚。
- 以上示例会确保当字段唯一值在 1000 以内时会得到非常准确的结果。只管算法是无法包管这点的,但假如基数在阈值以下,险些总是 100% 正确的。高于阈值的基数会开始节省内存而牺牲准确度,同时也会对度量结果带入误差。
- 对于指定的阈值,HLL 的数据布局会大概使用 precision_threshold * 8 字节的内存,所以就必须在牺牲内存和获得额外的准确度间做均衡。
- 在实际应用中, 100 的阈值可以在唯一值为百万的环境下仍然将误差维持 5% 以内。
五、collapse + cardinality 实现去重统计和查询
- {
- "query": {
- "bool": {
- "filter": [
- {
- "range": {
- "personid": {
- "lt": "1000000000"
- }
- }
- },
- {
- "term": {
- "isDeleted": "0"
- }
- }
- ]
- }
- },
- "collapse": {
- "field": "course_id"
- },
- "from": 0,
- "size": 10,
- "track_total_hits": true,
- "aggs": {
- "courseAgg": {
- "cardinality": {
- "field": "course_id"
- }
- }
- }
- }
复制代码 返回结果:
- {
- "took": 140,
- "timed_out": false,
- "_shards": {
- "total": 6,
- "successful": 6,
- "skipped": 0,
- "failed": 0
- },
- "hits": {
- "total": {
- "value": 2111,
- "relation": "eq"
- },
- "max_score": 0.0,
- "hits": [...]
- },
- "aggregations": {
- "courseAgg": {
- "value": 1070
- }
- }
- }
复制代码 解释阐明:
- hits中的total字段表现的总条数,实际上是查询结果在去重之前的总数目,也就是原始数据的条数。这个数值在分页功能中通常不会被直接使用。而hits数组的巨细与aggregations中的courseAgg聚合值相称,表示数组中展示的是去重后的数据。
- 在aggregations中的courseAgg条数,代表去重后的实际数据条数,这也是进行分页时所使用的关键数值,它指示了去重后可用于展示的总条数。
- from参数表示查询的起始位置,即从那里开始检索数据,它相称于查询的偏移量。
- size参数定义了每次查询返回的数据条数,即一次检索并展示多少条记录。
关注以下公众号获取更多深度内容,纯干货 !
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |