backend/app/services/index/Aggregations.scala (61 lines of code) (raw):
package services.index
import java.time.format.DateTimeFormatter
import java.time.{Instant, LocalDateTime, ZoneOffset}
import com.sksamuel.elastic4s.requests.searches.SearchResponse
import com.sksamuel.elastic4s.requests.searches.aggs.responses.bucket.{HistogramBucket, TermBucket, Terms}
import model.frontend.{SearchAggregation, SearchAggregationBucket}
object Aggregations {
private val yearsFormat = DateTimeFormatter.ofPattern("yyyy")
private val monthsFormat = DateTimeFormatter.ofPattern("MM")
def mimeTypes(resp: SearchResponse): SearchAggregation = {
val grouped = resp.aggregations.result[Terms](IndexAggNames.mimeTypes).buckets.groupBy(b => s"${b.key.split("/").head}/")
val aggs = grouped.map { case (mediaType, buckets) =>
SearchAggregationBucket(
mediaType,
buckets.foldLeft(0L)((a, i) => a + i.docCount),
Some(buckets.map(b => SearchAggregationBucket(b.key, b.docCount, None)).toList))
}.toList
SearchAggregation(IndexAggNames.mimeTypes, aggs)
}
def workspaces(resp: SearchResponse): SearchAggregation = {
SearchAggregation(IndexAggNames.workspace,
resp.aggregations.nested(IndexAggNames.workspace)
.result[Terms](IndexAggNames.workspace)
.buckets.map(bucket => SearchAggregationBucket(bucket.key, bucket.docCount, None)).toList
)
}
def months(resp: SearchResponse): SearchAggregation = {
val allBuckets = resp.aggregations.histogram(IndexAggNames.createdAt).buckets
val buckets = allBuckets.collect {
case HistogramBucket(raw, count, _) if count > 0 =>
val ts = LocalDateTime.ofInstant(Instant.ofEpochMilli(raw.toLong), ZoneOffset.UTC)
ts -> count
}
val aggs = buckets.groupBy { case(ts, _) => yearsFormat.format(ts) }.map { case(year, values) =>
val total = values.map(_._2).sum
SearchAggregationBucket(year, total, Some(values.toList.map { case(start, count) =>
SearchAggregationBucket(s"$year/${monthsFormat.format(start)}", count, None)
}))
}
SearchAggregation(IndexAggNames.createdAt, aggs.toList)
}
def collections(resp: SearchResponse): SearchAggregation = {
val collections = resp.aggregations.result[Terms](IndexAggNames.collection).buckets.toList
val ingestions = resp.aggregations.result[Terms](IndexAggNames.ingestion).buckets.toList
val aggs = collections.map { collection =>
val subAggs = ingestionsForCollection(collection.key, ingestions)
SearchAggregationBucket(collection.key, collection.docCount, subAggs)
}
SearchAggregation(IndexAggNames.ingestion, aggs)
}
private def ingestionsForCollection(collection: String, allIngestions: List[TermBucket]): Option[List[SearchAggregationBucket]] = {
allIngestions.filter(_.key.startsWith(s"$collection/")) match {
case Nil =>
None
case matchingIngestions =>
Some(matchingIngestions.map { ingestion =>
SearchAggregationBucket(ingestion.key, ingestion.docCount)
})
}
}
}