Article / 文章中心

Elasticsearch中nested聚合操作

发布时间:2021-11-24 点击数:414

ElasticSearch简介(也称ES)

Elasticsearch 是一个分布式可扩展的实时搜索和分析引擎,一个建立在全文搜索引擎 Apache Lucene(TM) 基础上的搜索引擎.当然 Elasticsearch 并不仅仅是 Lucene 那么简单,它不仅包括了全文搜索功能,还可以进行以下工作:

  • 分布式实时文件存储,并将每一个字段都编入索引,使其可以被搜索。
  • 实时分析的分布式搜索引擎。
  • 可以扩展到上百台服务器,处理PB级别的结构化或非结构化数据。

ElasticSearch数据类型

一级分类 二级分类 具体类型
基础类型 字符串类型 string,text,keyword
-- 整数类型 integer,long,short,byte
-- 逻辑类型 boolean
-- 浮点类型 double,float,half_float,scaled_float
-- 日期类型 date
-- 范围类型 range
-- 二进制类型 binary
复合类型 数组类型 array
-- 对象类型 object
-- 嵌套类型 nested
地理类型 地理坐标类型 geo_point
-- 地理地图 geo_shape
特殊类型 IP类型 ip
-- 范围地图 completion
-- 令牌计数类型 token_count
-- 附件地图 attachment
-- 抽取类型 percolator

以上便是ES中的数据类型,下面便对其中的object和nested来做一个简单的介绍。

nested介绍

nested就是一个嵌套对象,是object数据类型的特殊版本,它允许对象数组相互独立地进行索引和查询,使用时和其他类型使用基本相同,下面便是我来举的一个例子,labels便是一个nested类型的数据

{ "settings": { "index": { "codec": "best_compression", "mapping": { "nested_fields": { "limit": "2000" }, "total_fields": { "limit": "10000" }
      }, "refresh_interval": "1s", "number_of_shards": "2", "translog": { "flush_threshold_size": "1gb", "sync_interval": "30s", "durability": "async" }, "number_of_replicas": "1" }
  }, "mappings": { "dynamic": true, "properties": { "id": { "type": "long", "doc_values": false, "index": false }, "name": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_smart" }, "provinces": { "type": "keyword", "doc_values": false }, "city": { "type": "keyword" }, "permissionLevel": { "type": "integer", "doc_values": false, "index": false }, "status": { "type": "integer" }, "labels": { "type": "nested", "properties": { "label": { "type": "keyword" }, "classification": { "type": "keyword" }
        }
      }
    }
  }
}

当需要使用这个嵌套类型中的数据进行过滤,统计时我们普遍会使用这个来做一个聚合查询,但是这个会出现一个问题,那便是,所聚合出来的数据只是nested对象的数据,而外部主体数据并没有聚合出来那便是一个问题

{ "size": 0, "query": { "bool": { "must": [
        { "nested": { "path": "labels", "query": { "term": { "labels.classification": "行业" }
            }
          }
        }
      ]
    }
  }, "aggs": { "genres": { "nested": { "path": "labels" }, "aggs": { "label_agg": { "terms": { "field": "labels.label" }, "aggs": { "count_sub": { "sum": { "field": "viewCpount" }
            }
          }
        }, "fll": { "filter": { "term": { "labels.classification": "行业" }
          }, "aggs": { "label_agg2": { "terms": { "field": "labels.label" }
            }
          }
        }
      }
    }
  }
}

之后,通过对官网文档,还有同事的讨论,当对nested对象使用聚合查询时,便需要时用reverse_nested,来回到root主体。这样便能够对nested之外的数据来进行聚合操作了。

{ "size": 0, "query": { "bool": { "must": [
        { "nested": { "path": "labels", "query": { "term": { "labels.classification": "c1" }
            }
          }
        }
      ]
    }
  }, "aggs": { "genres": { "nested": { "path": "labels" }, "aggs": { "fll": { "filter": { "term": { "labels.classification": "c1" }
          }, "aggs": { "label_agg2": { "terms": { "field": "labels.label" }, "aggs": { "res": { "reverse_nested": {}, "aggs": { "count_view": { "sum": { "field": "viewCount" }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}```