1 /***********************************************************************
2  * Copyright (c) 2013-2025 General Atomics Integrated Intelligence, 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  * https://www.apache.org/licenses/LICENSE-2.0
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.GeoMesaStatWriter
17 import org.locationtech.geomesa.index.stats.impl._
18 import org.locationtech.geomesa.index.stats.{GeoMesaStats, Stat}
19 import org.locationtech.geomesa.lambda.stream.TransientStore
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 97681 1297 - 1314 Select org.locationtech.geomesa.index.stats.GeoMesaStats.writer LambdaStats.this.persistent.writer
29 97688 1437 - 1721 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 97683 1513 - 1516 Block <nosymbol> -1L
30 97682 1513 - 1516 Literal <nosymbol> -1L
31 97687 1530 - 1715 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 97685 1549 - 1701 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 97684 1627 - 1691 Throw <nosymbol> throw new java.lang.IllegalStateException("Transient stats returned None")
35 97686 1710 - 1715 Apply scala.Long.+ p.+(t)
44 97690 1890 - 2037 Apply scala.Option.getOrElse LambdaStats.this.transient(sft).getMinMax[T](sft, attribute, filter, exact).getOrElse[org.locationtech.geomesa.index.stats.impl.MinMax[T]](throw new java.lang.IllegalStateException("Transient stats returned None"))
45 97689 1967 - 2031 Throw <nosymbol> throw new java.lang.IllegalStateException("Transient stats returned None")
47 97691 2101 - 2106 Apply org.locationtech.geomesa.index.stats.impl.MinMax.+ x$1.+(t)
47 97693 2042 - 2123 Apply scala.Option.orElse LambdaStats.this.persistent.getMinMax[T](sft, attribute, filter, exact).map[org.locationtech.geomesa.index.stats.impl.MinMax[T]](((x$1: org.locationtech.geomesa.index.stats.impl.MinMax[T]) => x$1.+(t))).orElse[org.locationtech.geomesa.index.stats.impl.MinMax[T]](scala.Some.apply[org.locationtech.geomesa.index.stats.impl.MinMax[T]](t))
47 97692 2115 - 2122 Apply scala.Some.apply scala.Some.apply[org.locationtech.geomesa.index.stats.impl.MinMax[T]](t)
55 97694 2308 - 2367 Apply org.locationtech.geomesa.index.stats.GeoMesaStats.getEnumeration LambdaStats.this.persistent.getEnumeration[T](sft, attribute, filter, exact)
56 97695 2376 - 2382 Select scala.Boolean.unary_! exact.unary_!
56 97696 2386 - 2389 Ident org.locationtech.geomesa.lambda.data.LambdaStats.per per
57 97697 2490 - 2495 Apply org.locationtech.geomesa.index.stats.impl.EnumerationStat.+ x$2.+(p)
57 97699 2405 - 2497 Apply scala.Option.flatMap per.flatMap[org.locationtech.geomesa.index.stats.impl.EnumerationStat[T]](((p: org.locationtech.geomesa.index.stats.impl.EnumerationStat[T]) => LambdaStats.this.transient(sft).getEnumeration[T](sft, attribute, filter, exact).map[org.locationtech.geomesa.index.stats.impl.EnumerationStat[T]](((x$2: org.locationtech.geomesa.index.stats.impl.EnumerationStat[T]) => x$2.+(p)))))
57 97698 2422 - 2496 Apply scala.Option.map LambdaStats.this.transient(sft).getEnumeration[T](sft, attribute, filter, exact).map[org.locationtech.geomesa.index.stats.impl.EnumerationStat[T]](((x$2: org.locationtech.geomesa.index.stats.impl.EnumerationStat[T]) => x$2.+(p)))
57 97700 2405 - 2497 Block scala.Option.flatMap per.flatMap[org.locationtech.geomesa.index.stats.impl.EnumerationStat[T]](((p: org.locationtech.geomesa.index.stats.impl.EnumerationStat[T]) => LambdaStats.this.transient(sft).getEnumeration[T](sft, attribute, filter, exact).map[org.locationtech.geomesa.index.stats.impl.EnumerationStat[T]](((x$2: org.locationtech.geomesa.index.stats.impl.EnumerationStat[T]) => x$2.+(p)))))
67 97701 2702 - 2770 Apply org.locationtech.geomesa.index.stats.GeoMesaStats.getFrequency LambdaStats.this.persistent.getFrequency[T](sft, attribute, precision, filter, exact)
68 97703 2789 - 2792 Ident org.locationtech.geomesa.lambda.data.LambdaStats.per per
68 97702 2779 - 2785 Select scala.Boolean.unary_! exact.unary_!
69 97705 2825 - 2908 Apply scala.Option.map LambdaStats.this.transient(sft).getFrequency[T](sft, attribute, precision, filter, exact).map[org.locationtech.geomesa.index.stats.impl.Frequency[T]](((x$3: org.locationtech.geomesa.index.stats.impl.Frequency[T]) => x$3.+(p)))
69 97704 2902 - 2907 Apply org.locationtech.geomesa.index.stats.impl.Frequency.+ x$3.+(p)
69 97707 2808 - 2909 Block scala.Option.flatMap per.flatMap[org.locationtech.geomesa.index.stats.impl.Frequency[T]](((p: org.locationtech.geomesa.index.stats.impl.Frequency[T]) => LambdaStats.this.transient(sft).getFrequency[T](sft, attribute, precision, filter, exact).map[org.locationtech.geomesa.index.stats.impl.Frequency[T]](((x$3: org.locationtech.geomesa.index.stats.impl.Frequency[T]) => x$3.+(p)))))
69 97706 2808 - 2909 Apply scala.Option.flatMap per.flatMap[org.locationtech.geomesa.index.stats.impl.Frequency[T]](((p: org.locationtech.geomesa.index.stats.impl.Frequency[T]) => LambdaStats.this.transient(sft).getFrequency[T](sft, attribute, precision, filter, exact).map[org.locationtech.geomesa.index.stats.impl.Frequency[T]](((x$3: org.locationtech.geomesa.index.stats.impl.Frequency[T]) => x$3.+(p)))))
78 97708 3082 - 3134 Apply org.locationtech.geomesa.index.stats.GeoMesaStats.getTopK LambdaStats.this.persistent.getTopK[T](sft, attribute, filter, exact)
79 97709 3143 - 3149 Select scala.Boolean.unary_! exact.unary_!
79 97710 3153 - 3156 Ident org.locationtech.geomesa.lambda.data.LambdaStats.per per
80 97711 3250 - 3255 Apply org.locationtech.geomesa.index.stats.impl.TopK.+ x$4.+(p)
80 97713 3172 - 3257 Apply scala.Option.flatMap per.flatMap[org.locationtech.geomesa.index.stats.impl.TopK[T]](((p: org.locationtech.geomesa.index.stats.impl.TopK[T]) => LambdaStats.this.transient(sft).getTopK[T](sft, attribute, filter, exact).map[org.locationtech.geomesa.index.stats.impl.TopK[T]](((x$4: org.locationtech.geomesa.index.stats.impl.TopK[T]) => x$4.+(p)))))
80 97712 3189 - 3256 Apply scala.Option.map LambdaStats.this.transient(sft).getTopK[T](sft, attribute, filter, exact).map[org.locationtech.geomesa.index.stats.impl.TopK[T]](((x$4: org.locationtech.geomesa.index.stats.impl.TopK[T]) => x$4.+(p)))
80 97714 3172 - 3257 Block scala.Option.flatMap per.flatMap[org.locationtech.geomesa.index.stats.impl.TopK[T]](((p: org.locationtech.geomesa.index.stats.impl.TopK[T]) => LambdaStats.this.transient(sft).getTopK[T](sft, attribute, filter, exact).map[org.locationtech.geomesa.index.stats.impl.TopK[T]](((x$4: org.locationtech.geomesa.index.stats.impl.TopK[T]) => x$4.+(p)))))
92 97715 3485 - 3558 Apply org.locationtech.geomesa.index.stats.GeoMesaStats.getHistogram LambdaStats.this.persistent.getHistogram[T](sft, attribute, bins, min, max, filter, exact)
93 97717 3577 - 3580 Ident org.locationtech.geomesa.lambda.data.LambdaStats.per per
93 97716 3567 - 3573 Select scala.Boolean.unary_! exact.unary_!
94 97719 3613 - 3701 Apply scala.Option.map LambdaStats.this.transient(sft).getHistogram[T](sft, attribute, bins, min, max, filter, exact).map[org.locationtech.geomesa.index.stats.impl.Histogram[T]](((x$5: org.locationtech.geomesa.index.stats.impl.Histogram[T]) => x$5.+(p)))
94 97718 3695 - 3700 Apply org.locationtech.geomesa.index.stats.impl.Histogram.+ x$5.+(p)
94 97721 3596 - 3702 Block scala.Option.flatMap per.flatMap[org.locationtech.geomesa.index.stats.impl.Histogram[T]](((p: org.locationtech.geomesa.index.stats.impl.Histogram[T]) => LambdaStats.this.transient(sft).getHistogram[T](sft, attribute, bins, min, max, filter, exact).map[org.locationtech.geomesa.index.stats.impl.Histogram[T]](((x$5: org.locationtech.geomesa.index.stats.impl.Histogram[T]) => x$5.+(p)))))
94 97720 3596 - 3702 Apply scala.Option.flatMap per.flatMap[org.locationtech.geomesa.index.stats.impl.Histogram[T]](((p: org.locationtech.geomesa.index.stats.impl.Histogram[T]) => LambdaStats.this.transient(sft).getHistogram[T](sft, attribute, bins, min, max, filter, exact).map[org.locationtech.geomesa.index.stats.impl.Histogram[T]](((x$5: org.locationtech.geomesa.index.stats.impl.Histogram[T]) => x$5.+(p)))))
106 97722 3940 - 4010 Apply org.locationtech.geomesa.index.stats.GeoMesaStats.getZ3Histogram LambdaStats.this.persistent.getZ3Histogram(sft, geom, dtg, period, bins, filter, exact)
107 97723 4019 - 4025 Select scala.Boolean.unary_! exact.unary_!
107 97724 4029 - 4032 Ident org.locationtech.geomesa.lambda.data.LambdaStats.per per
108 97725 4144 - 4149 Apply org.locationtech.geomesa.index.stats.impl.Z3Histogram.+ x$6.+(p)
108 97727 4048 - 4151 Apply scala.Option.flatMap per.flatMap[org.locationtech.geomesa.index.stats.impl.Z3Histogram](((p: org.locationtech.geomesa.index.stats.impl.Z3Histogram) => LambdaStats.this.transient(sft).getZ3Histogram(sft, geom, dtg, period, bins, filter, exact).map[org.locationtech.geomesa.index.stats.impl.Z3Histogram](((x$6: org.locationtech.geomesa.index.stats.impl.Z3Histogram) => x$6.+(p)))))
108 97726 4065 - 4150 Apply scala.Option.map LambdaStats.this.transient(sft).getZ3Histogram(sft, geom, dtg, period, bins, filter, exact).map[org.locationtech.geomesa.index.stats.impl.Z3Histogram](((x$6: org.locationtech.geomesa.index.stats.impl.Z3Histogram) => x$6.+(p)))
108 97728 4048 - 4151 Block scala.Option.flatMap per.flatMap[org.locationtech.geomesa.index.stats.impl.Z3Histogram](((p: org.locationtech.geomesa.index.stats.impl.Z3Histogram) => LambdaStats.this.transient(sft).getZ3Histogram(sft, geom, dtg, period, bins, filter, exact).map[org.locationtech.geomesa.index.stats.impl.Z3Histogram](((x$6: org.locationtech.geomesa.index.stats.impl.Z3Histogram) => x$6.+(p)))))
117 97729 4322 - 4370 Apply org.locationtech.geomesa.index.stats.GeoMesaStats.getStat LambdaStats.this.persistent.getStat[T](sft, query, filter, exact)
118 97731 4389 - 4392 Ident org.locationtech.geomesa.lambda.data.LambdaStats.per per
118 97730 4379 - 4385 Select scala.Boolean.unary_! exact.unary_!
119 97733 4482 - 4487 ApplyToImplicitArgs org.locationtech.geomesa.index.stats.Stat.+ x$7.+(p)(Predef.this.DummyImplicit.dummyImplicit)
119 97732 4484 - 4484 Select scala.Predef.DummyImplicit.dummyImplicit Predef.this.DummyImplicit.dummyImplicit
119 97735 4408 - 4513 TypeApply scala.Any.asInstanceOf per.flatMap[org.locationtech.geomesa.index.stats.Stat](((p: T) => LambdaStats.this.transient(sft).getStat[T](sft, query, filter, exact).map[org.locationtech.geomesa.index.stats.Stat](((x$7: T) => x$7.+(p)(Predef.this.DummyImplicit.dummyImplicit))))).asInstanceOf[Option[T]]
119 97734 4425 - 4488 Apply scala.Option.map LambdaStats.this.transient(sft).getStat[T](sft, query, filter, exact).map[org.locationtech.geomesa.index.stats.Stat](((x$7: T) => x$7.+(p)(Predef.this.DummyImplicit.dummyImplicit)))
119 97736 4408 - 4513 Block scala.Any.asInstanceOf per.flatMap[org.locationtech.geomesa.index.stats.Stat](((p: T) => LambdaStats.this.transient(sft).getStat[T](sft, query, filter, exact).map[org.locationtech.geomesa.index.stats.Stat](((x$7: T) => x$7.+(p)(Predef.this.DummyImplicit.dummyImplicit))))).asInstanceOf[Option[T]]
124 97737 4634 - 4636 Literal <nosymbol> ()
126 97739 4702 - 4739 Select org.locationtech.geomesa.lambda.stream.TransientStore.stats LambdaStats.this.transients.get(sft.getTypeName()).stats
126 97738 4717 - 4732 Apply org.geotools.api.feature.simple.SimpleFeatureType.getTypeName sft.getTypeName()