简体   繁体   English

使用elastic4s客户端为Elasticsearch构建动态聚合查询

[英]Building dynamic aggregation queries for elasticsearch using elastic4s client

Is it possible to do multi level aggregation queries dynamically using elastic4s DSL. 是否可以使用elastic4s DSL动态进行多级聚合查询。

Using http client its straightforward 使用HTTP客户端非常简单

multiLevelAggregation

 Input: Fields[0..N]
 Output: Data grouped by field tuple

 Steps:
 1.  Build multilevel elasticsearch aggregation query (JSON)
 2.  Execute query on elasticsearch server
 3.  Flatten result and return

But how to do this using elastic4s or Java client. 但是如何使用elastic4s或Java客户端执行此操作。

After understanding my problem carefully I managed to find a solution to this, initially I thought this would be limitation of elastic4s but its not so, its easy to dynamically build multi field aggregation queries via elastic4s client, Here is my solution 在认真理解了我的问题之后,我设法找到了解决方案,最初我以为这是对Elastic4s的限制,但事实并非如此,它易于通过elastic4s客户端动态构建多字段聚合查询,这是我的解决方案

//For building aggregation query
def buildAgg(groups: Seq[String])(leafAggBuilder: () => AbstractAggregationDefinition): AbstractAggregationDefinition = {
  groups match {
    case x :: xs => aggregation.terms("termAgg").field(x).aggregations(buildAgg(xs)(leafAggBuilder))
    case Nil => leafAggBuilder()
  }
}

//An example leaf aggregation builder
def buildLeafAgg(aggFuncInfo: Pair[String, String])(): AbstractAggregationDefinition = {
  aggFuncInfo._1 match {
    case "avg" => aggregation.avg("aggFunc").field(aggFuncInfo._2)
    case "sum" => aggregation.sum("aggFunc").field(aggFuncInfo._2)
    case "cardinality" => aggregation.cardinality("aggFunc").field(aggFuncInfo._2)
    case _ => aggregation.count("aggFunc").field(aggFuncInfo._2)
  }
}

//For parsing aggregation
def parseAgg[T](groups: Seq[String], agg: Aggregation, allGroups: Seq[String])(leafAggParser: (Seq[String], Aggregation) => Seq[T]): Seq[T] = {
  groups match {
    case x :: xs => {
      val groupAggs = agg.asInstanceOf[StringTerms].getBuckets.asScala.toList
      (for {
        groupAgg <- groupAggs
        aa = groupAgg.getAggregations.asList.asScala.head
        gkey = groupAgg.getKeyAsString
        gacc = allGroups :+ gkey
      } yield parseAgg(xs, aa, gacc)(leafAggParser)).flatten
    }

    case Nil => {
      leafAggParser(allGroups, agg)
    }
  }
}

//An example leaf aggregation parser
def parseSimpleLeafAgg(allGroups: Seq[String], agg: Aggregation): Seq[GroupStats] = {
  val value = agg.asInstanceOf[InternalNumericMetricsAggregation.SingleValue].value()
  val groupId = allGroups.mkString(".")
  Seq(GroupStats(groupId, value))
}

//Usage: Build Query and Parse result
def groupStats(groupFields: Seq[String]): Seq[GroupStats] = {
  val resp = client.execute {
    def leafPlainAggBuilder = buildLeafAgg(("count", "V1")) _
    search(esIndex).size(0).aggregations(buildAgg(groupFields)(leafPlainAggBuilder))
  }.await
  //get the root aggregation
  val agg = resp.aggregations.asList().asScala.head
  def leafAggParser = parseSimpleLeafAgg _
  val res = parseAgg(groupFields, agg, Seq())(leafAggParser)
  res
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM