1 /***********************************************************************
2  * Copyright (c) 2013-2024 Commonwealth Computer Research, Inc.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Apache License, Version 2.0
5  * which accompanies this distribution and is available at
6  * http://www.opensource.org/licenses/apache2.0.php.
7  ***********************************************************************/
8 
9 package org.locationtech.geomesa.lambda.data
10 
11 import com.github.benmanes.caffeine.cache.LoadingCache
12 import org.geotools.api.feature.simple.SimpleFeatureType
13 import org.geotools.api.filter.Filter
14 import org.geotools.util.factory.Hints
15 import org.locationtech.geomesa.curve.TimePeriod.TimePeriod
16 import org.locationtech.geomesa.index.stats.GeoMesaStats
17 import org.locationtech.geomesa.index.stats.GeoMesaStats.GeoMesaStatWriter
18 import org.locationtech.geomesa.lambda.stream.TransientStore
19 import org.locationtech.geomesa.utils.stats._
20 
21 class LambdaStats(persistent: GeoMesaStats, transients: LoadingCache[String, TransientStore]) extends GeoMesaStats {
22 
23   // note: transient stat methods always return Some for Count and MinMax,
24   // but otherwise return None if not exact
25 
26   override def writer: GeoMesaStatWriter = persistent.writer
27 
28   override def getCount(sft: SimpleFeatureType, filter: Filter, exact: Boolean, queryHints: Hints): Option[Long] = {
29     persistent.getCount(sft, filter, exact, queryHints).map {
30       case -1L => -1L
31       case p =>
32         val t = transient(sft).getCount(sft, filter, exact, queryHints).getOrElse {
33           throw new IllegalStateException("Transient stats returned None")
34         }
35         p + t
36     }
37   }
38 
39   override def getMinMax[T](
40       sft: SimpleFeatureType,
41       attribute: String,
42       filter: Filter,
43       exact: Boolean): Option[MinMax[T]] = {
44     val t = transient(sft).getMinMax[T](sft, attribute, filter, exact).getOrElse {
45       throw new IllegalStateException("Transient stats returned None")
46     }
47     persistent.getMinMax[T](sft, attribute, filter, exact).map(_ + t).orElse(Some(t))
48   }
49 
50   override def getEnumeration[T](
51       sft: SimpleFeatureType,
52       attribute: String,
53       filter: Filter,
54       exact: Boolean): Option[EnumerationStat[T]] = {
55     val per = persistent.getEnumeration[T](sft, attribute, filter, exact)
56     if (!exact) { per } else {
57       per.flatMap(p => transient(sft).getEnumeration[T](sft, attribute, filter, exact).map(_ + p))
58     }
59   }
60 
61   override def getFrequency[T](
62       sft: SimpleFeatureType,
63       attribute: String,
64       precision: Int,
65       filter: Filter,
66       exact: Boolean): Option[Frequency[T]] = {
67     val per = persistent.getFrequency[T](sft, attribute, precision, filter, exact)
68     if (!exact) { per } else {
69       per.flatMap(p => transient(sft).getFrequency[T](sft, attribute, precision, filter, exact).map(_ + p))
70     }
71   }
72 
73   override def getTopK[T](
74       sft: SimpleFeatureType,
75       attribute: String,
76       filter: Filter,
77       exact: Boolean): Option[TopK[T]] = {
78     val per = persistent.getTopK[T](sft, attribute, filter, exact)
79     if (!exact) { per } else {
80       per.flatMap(p => transient(sft).getTopK[T](sft, attribute, filter, exact).map(_ + p))
81     }
82   }
83 
84   override def getHistogram[T](
85       sft: SimpleFeatureType,
86       attribute: String,
87       bins: Int,
88       min: T,
89       max: T,
90       filter: Filter,
91       exact: Boolean): Option[Histogram[T]] = {
92     val per = persistent.getHistogram[T](sft, attribute, bins, min, max, filter, exact)
93     if (!exact) { per } else {
94       per.flatMap(p => transient(sft).getHistogram[T](sft, attribute, bins, min, max, filter, exact).map(_ + p))
95     }
96   }
97 
98   override def getZ3Histogram(
99       sft: SimpleFeatureType,
100       geom: String,
101       dtg: String,
102       period: TimePeriod,
103       bins: Int,
104       filter: Filter,
105       exact: Boolean): Option[Z3Histogram] = {
106     val per = persistent.getZ3Histogram(sft, geom, dtg, period, bins, filter, exact)
107     if (!exact) { per } else {
108       per.flatMap(p => transient(sft).getZ3Histogram(sft, geom, dtg, period, bins, filter, exact).map(_ + p))
109     }
110   }
111 
112   override def getStat[T <: Stat](
113       sft: SimpleFeatureType,
114       query: String,
115       filter: Filter,
116       exact: Boolean): Option[T] = {
117     val per = persistent.getStat[T](sft, query, filter, exact)
118     if (!exact) { per } else {
119       per.flatMap(p => transient(sft).getStat[T](sft, query, filter, exact).map(_ + p)).asInstanceOf[Option[T]]
120     }
121   }
122 
123   // note: closed by closing the wrapping stores in LambdaDataStore.dispose()
124   override def close(): Unit = {}
125 
126   private def transient(sft: SimpleFeatureType): GeoMesaStats = transients.get(sft.getTypeName).stats
127 }
Line Stmt Id Pos Tree Symbol Tests Code
26 96454 1281 - 1298 Select org.locationtech.geomesa.index.stats.GeoMesaStats.writer LambdaStats.this.persistent.writer
29 96461 1421 - 1705 Apply scala.Option.map LambdaStats.this.persistent.getCount(sft, filter, exact, queryHints).map[Long](((x0$1: Long) => x0$1 match { case -1L => -1L case (p @ _) => { val t: Long = LambdaStats.this.transient(sft).getCount(sft, filter, exact, queryHints).getOrElse[Long](throw new java.lang.IllegalStateException("Transient stats returned None")); p.+(t) } }))
30 96455 1497 - 1500 Literal <nosymbol> -1L
30 96456 1497 - 1500 Block <nosymbol> -1L
31 96460 1514 - 1699 Block <nosymbol> { val t: Long = LambdaStats.this.transient(sft).getCount(sft, filter, exact, queryHints).getOrElse[Long](throw new java.lang.IllegalStateException("Transient stats returned None")); p.+(t) }
32 96458 1533 - 1685 Apply scala.Option.getOrElse LambdaStats.this.transient(sft).getCount(sft, filter, exact, queryHints).getOrElse[Long](throw new java.lang.IllegalStateException("Transient stats returned None"))
33 96457 1611 - 1675 Throw <nosymbol> throw new java.lang.IllegalStateException("Transient stats returned None")
35 96459 1694 - 1699 Apply scala.Long.+ p.+(t)
44 96463 1874 - 2021 Apply scala.Option.getOrElse LambdaStats.this.transient(sft).getMinMax[T](sft, attribute, filter, exact).getOrElse[org.locationtech.geomesa.utils.stats.MinMax[T]](throw new java.lang.IllegalStateException("Transient stats returned None"))
45 96462 1951 - 2015 Throw <nosymbol> throw new java.lang.IllegalStateException("Transient stats returned None")
47 96465 2099 - 2106 Apply scala.Some.apply scala.Some.apply[org.locationtech.geomesa.utils.stats.MinMax[T]](t)
47 96464 2085 - 2090 Apply org.locationtech.geomesa.utils.stats.MinMax.+ x$1.+(t)
47 96466 2026 - 2107 Apply scala.Option.orElse LambdaStats.this.persistent.getMinMax[T](sft, attribute, filter, exact).map[org.locationtech.geomesa.utils.stats.MinMax[T]](((x$1: org.locationtech.geomesa.utils.stats.MinMax[T]) => x$1.+(t))).orElse[org.locationtech.geomesa.utils.stats.MinMax[T]](scala.Some.apply[org.locationtech.geomesa.utils.stats.MinMax[T]](t))
55 96467 2292 - 2351 Apply org.locationtech.geomesa.index.stats.GeoMesaStats.getEnumeration LambdaStats.this.persistent.getEnumeration[T](sft, attribute, filter, exact)
56 96469 2370 - 2373 Ident org.locationtech.geomesa.lambda.data.LambdaStats.per per
56 96468 2360 - 2366 Select scala.Boolean.unary_! exact.unary_!
57 96471 2406 - 2480 Apply scala.Option.map LambdaStats.this.transient(sft).getEnumeration[T](sft, attribute, filter, exact).map[org.locationtech.geomesa.utils.stats.EnumerationStat[T]](((x$2: org.locationtech.geomesa.utils.stats.EnumerationStat[T]) => x$2.+(p)))
57 96470 2474 - 2479 Apply org.locationtech.geomesa.utils.stats.EnumerationStat.+ x$2.+(p)
57 96473 2389 - 2481 Block scala.Option.flatMap per.flatMap[org.locationtech.geomesa.utils.stats.EnumerationStat[T]](((p: org.locationtech.geomesa.utils.stats.EnumerationStat[T]) => LambdaStats.this.transient(sft).getEnumeration[T](sft, attribute, filter, exact).map[org.locationtech.geomesa.utils.stats.EnumerationStat[T]](((x$2: org.locationtech.geomesa.utils.stats.EnumerationStat[T]) => x$2.+(p)))))
57 96472 2389 - 2481 Apply scala.Option.flatMap per.flatMap[org.locationtech.geomesa.utils.stats.EnumerationStat[T]](((p: org.locationtech.geomesa.utils.stats.EnumerationStat[T]) => LambdaStats.this.transient(sft).getEnumeration[T](sft, attribute, filter, exact).map[org.locationtech.geomesa.utils.stats.EnumerationStat[T]](((x$2: org.locationtech.geomesa.utils.stats.EnumerationStat[T]) => x$2.+(p)))))
67 96474 2686 - 2754 Apply org.locationtech.geomesa.index.stats.GeoMesaStats.getFrequency LambdaStats.this.persistent.getFrequency[T](sft, attribute, precision, filter, exact)
68 96475 2763 - 2769 Select scala.Boolean.unary_! exact.unary_!
68 96476 2773 - 2776 Ident org.locationtech.geomesa.lambda.data.LambdaStats.per per
69 96477 2886 - 2891 Apply org.locationtech.geomesa.utils.stats.Frequency.+ x$3.+(p)
69 96479 2792 - 2893 Apply scala.Option.flatMap per.flatMap[org.locationtech.geomesa.utils.stats.Frequency[T]](((p: org.locationtech.geomesa.utils.stats.Frequency[T]) => LambdaStats.this.transient(sft).getFrequency[T](sft, attribute, precision, filter, exact).map[org.locationtech.geomesa.utils.stats.Frequency[T]](((x$3: org.locationtech.geomesa.utils.stats.Frequency[T]) => x$3.+(p)))))
69 96478 2809 - 2892 Apply scala.Option.map LambdaStats.this.transient(sft).getFrequency[T](sft, attribute, precision, filter, exact).map[org.locationtech.geomesa.utils.stats.Frequency[T]](((x$3: org.locationtech.geomesa.utils.stats.Frequency[T]) => x$3.+(p)))
69 96480 2792 - 2893 Block scala.Option.flatMap per.flatMap[org.locationtech.geomesa.utils.stats.Frequency[T]](((p: org.locationtech.geomesa.utils.stats.Frequency[T]) => LambdaStats.this.transient(sft).getFrequency[T](sft, attribute, precision, filter, exact).map[org.locationtech.geomesa.utils.stats.Frequency[T]](((x$3: org.locationtech.geomesa.utils.stats.Frequency[T]) => x$3.+(p)))))
78 96481 3066 - 3118 Apply org.locationtech.geomesa.index.stats.GeoMesaStats.getTopK LambdaStats.this.persistent.getTopK[T](sft, attribute, filter, exact)
79 96483 3137 - 3140 Ident org.locationtech.geomesa.lambda.data.LambdaStats.per per
79 96482 3127 - 3133 Select scala.Boolean.unary_! exact.unary_!
80 96485 3173 - 3240 Apply scala.Option.map LambdaStats.this.transient(sft).getTopK[T](sft, attribute, filter, exact).map[org.locationtech.geomesa.utils.stats.TopK[T]](((x$4: org.locationtech.geomesa.utils.stats.TopK[T]) => x$4.+(p)))
80 96484 3234 - 3239 Apply org.locationtech.geomesa.utils.stats.TopK.+ x$4.+(p)
80 96487 3156 - 3241 Block scala.Option.flatMap per.flatMap[org.locationtech.geomesa.utils.stats.TopK[T]](((p: org.locationtech.geomesa.utils.stats.TopK[T]) => LambdaStats.this.transient(sft).getTopK[T](sft, attribute, filter, exact).map[org.locationtech.geomesa.utils.stats.TopK[T]](((x$4: org.locationtech.geomesa.utils.stats.TopK[T]) => x$4.+(p)))))
80 96486 3156 - 3241 Apply scala.Option.flatMap per.flatMap[org.locationtech.geomesa.utils.stats.TopK[T]](((p: org.locationtech.geomesa.utils.stats.TopK[T]) => LambdaStats.this.transient(sft).getTopK[T](sft, attribute, filter, exact).map[org.locationtech.geomesa.utils.stats.TopK[T]](((x$4: org.locationtech.geomesa.utils.stats.TopK[T]) => x$4.+(p)))))
92 96488 3469 - 3542 Apply org.locationtech.geomesa.index.stats.GeoMesaStats.getHistogram LambdaStats.this.persistent.getHistogram[T](sft, attribute, bins, min, max, filter, exact)
93 96489 3551 - 3557 Select scala.Boolean.unary_! exact.unary_!
93 96490 3561 - 3564 Ident org.locationtech.geomesa.lambda.data.LambdaStats.per per
94 96491 3679 - 3684 Apply org.locationtech.geomesa.utils.stats.Histogram.+ x$5.+(p)
94 96493 3580 - 3686 Apply scala.Option.flatMap per.flatMap[org.locationtech.geomesa.utils.stats.Histogram[T]](((p: org.locationtech.geomesa.utils.stats.Histogram[T]) => LambdaStats.this.transient(sft).getHistogram[T](sft, attribute, bins, min, max, filter, exact).map[org.locationtech.geomesa.utils.stats.Histogram[T]](((x$5: org.locationtech.geomesa.utils.stats.Histogram[T]) => x$5.+(p)))))
94 96492 3597 - 3685 Apply scala.Option.map LambdaStats.this.transient(sft).getHistogram[T](sft, attribute, bins, min, max, filter, exact).map[org.locationtech.geomesa.utils.stats.Histogram[T]](((x$5: org.locationtech.geomesa.utils.stats.Histogram[T]) => x$5.+(p)))
94 96494 3580 - 3686 Block scala.Option.flatMap per.flatMap[org.locationtech.geomesa.utils.stats.Histogram[T]](((p: org.locationtech.geomesa.utils.stats.Histogram[T]) => LambdaStats.this.transient(sft).getHistogram[T](sft, attribute, bins, min, max, filter, exact).map[org.locationtech.geomesa.utils.stats.Histogram[T]](((x$5: org.locationtech.geomesa.utils.stats.Histogram[T]) => x$5.+(p)))))
106 96495 3924 - 3994 Apply org.locationtech.geomesa.index.stats.GeoMesaStats.getZ3Histogram LambdaStats.this.persistent.getZ3Histogram(sft, geom, dtg, period, bins, filter, exact)
107 96497 4013 - 4016 Ident org.locationtech.geomesa.lambda.data.LambdaStats.per per
107 96496 4003 - 4009 Select scala.Boolean.unary_! exact.unary_!
108 96499 4049 - 4134 Apply scala.Option.map LambdaStats.this.transient(sft).getZ3Histogram(sft, geom, dtg, period, bins, filter, exact).map[org.locationtech.geomesa.utils.stats.Z3Histogram](((x$6: org.locationtech.geomesa.utils.stats.Z3Histogram) => x$6.+(p)))
108 96498 4128 - 4133 Apply org.locationtech.geomesa.utils.stats.Z3Histogram.+ x$6.+(p)
108 96501 4032 - 4135 Block scala.Option.flatMap per.flatMap[org.locationtech.geomesa.utils.stats.Z3Histogram](((p: org.locationtech.geomesa.utils.stats.Z3Histogram) => LambdaStats.this.transient(sft).getZ3Histogram(sft, geom, dtg, period, bins, filter, exact).map[org.locationtech.geomesa.utils.stats.Z3Histogram](((x$6: org.locationtech.geomesa.utils.stats.Z3Histogram) => x$6.+(p)))))
108 96500 4032 - 4135 Apply scala.Option.flatMap per.flatMap[org.locationtech.geomesa.utils.stats.Z3Histogram](((p: org.locationtech.geomesa.utils.stats.Z3Histogram) => LambdaStats.this.transient(sft).getZ3Histogram(sft, geom, dtg, period, bins, filter, exact).map[org.locationtech.geomesa.utils.stats.Z3Histogram](((x$6: org.locationtech.geomesa.utils.stats.Z3Histogram) => x$6.+(p)))))
117 96502 4306 - 4354 Apply org.locationtech.geomesa.index.stats.GeoMesaStats.getStat LambdaStats.this.persistent.getStat[T](sft, query, filter, exact)
118 96503 4363 - 4369 Select scala.Boolean.unary_! exact.unary_!
118 96504 4373 - 4376 Ident org.locationtech.geomesa.lambda.data.LambdaStats.per per
119 96505 4468 - 4468 Select scala.Predef.DummyImplicit.dummyImplicit Predef.this.DummyImplicit.dummyImplicit
119 96507 4409 - 4472 Apply scala.Option.map LambdaStats.this.transient(sft).getStat[T](sft, query, filter, exact).map[org.locationtech.geomesa.utils.stats.Stat](((x$7: T) => x$7.+(p)(Predef.this.DummyImplicit.dummyImplicit)))
119 96506 4466 - 4471 ApplyToImplicitArgs org.locationtech.geomesa.utils.stats.Stat.+ x$7.+(p)(Predef.this.DummyImplicit.dummyImplicit)
119 96509 4392 - 4497 Block scala.Any.asInstanceOf per.flatMap[org.locationtech.geomesa.utils.stats.Stat](((p: T) => LambdaStats.this.transient(sft).getStat[T](sft, query, filter, exact).map[org.locationtech.geomesa.utils.stats.Stat](((x$7: T) => x$7.+(p)(Predef.this.DummyImplicit.dummyImplicit))))).asInstanceOf[Option[T]]
119 96508 4392 - 4497 TypeApply scala.Any.asInstanceOf per.flatMap[org.locationtech.geomesa.utils.stats.Stat](((p: T) => LambdaStats.this.transient(sft).getStat[T](sft, query, filter, exact).map[org.locationtech.geomesa.utils.stats.Stat](((x$7: T) => x$7.+(p)(Predef.this.DummyImplicit.dummyImplicit))))).asInstanceOf[Option[T]]
124 96510 4618 - 4620 Literal <nosymbol> ()
126 96511 4701 - 4716 Apply org.geotools.api.feature.simple.SimpleFeatureType.getTypeName sft.getTypeName()
126 96512 4686 - 4723 Select org.locationtech.geomesa.lambda.stream.TransientStore.stats LambdaStats.this.transients.get(sft.getTypeName()).stats