diff --git a/coordinator/src/main/scala/filodb/coordinator/ProtoConverters.scala b/coordinator/src/main/scala/filodb/coordinator/ProtoConverters.scala index a2a744a86b..9fdf537bf2 100644 --- a/coordinator/src/main/scala/filodb/coordinator/ProtoConverters.scala +++ b/coordinator/src/main/scala/filodb/coordinator/ProtoConverters.scala @@ -1429,6 +1429,7 @@ object ProtoConverters { case AggregationOperator.BottomK => GrpcMultiPartitionQueryService.AggregationOperator.BOTTOM_K case AggregationOperator.Min => GrpcMultiPartitionQueryService.AggregationOperator.MIN case AggregationOperator.Avg => GrpcMultiPartitionQueryService.AggregationOperator.AVG + case AggregationOperator.HAvg => GrpcMultiPartitionQueryService.AggregationOperator.HAVG case AggregationOperator.Sum => GrpcMultiPartitionQueryService.AggregationOperator.SUM case AggregationOperator.Stddev => GrpcMultiPartitionQueryService.AggregationOperator.STDDEV case AggregationOperator.Stdvar => GrpcMultiPartitionQueryService.AggregationOperator.STDVAR @@ -1448,6 +1449,7 @@ object ProtoConverters { case GrpcMultiPartitionQueryService.AggregationOperator.BOTTOM_K => AggregationOperator.BottomK case GrpcMultiPartitionQueryService.AggregationOperator.MIN => AggregationOperator.Min case GrpcMultiPartitionQueryService.AggregationOperator.AVG => AggregationOperator.Avg + case GrpcMultiPartitionQueryService.AggregationOperator.HAVG => AggregationOperator.HAvg case GrpcMultiPartitionQueryService.AggregationOperator.SUM => AggregationOperator.Sum case GrpcMultiPartitionQueryService.AggregationOperator.STDDEV => AggregationOperator.Stddev case GrpcMultiPartitionQueryService.AggregationOperator.STDVAR => AggregationOperator.Stdvar diff --git a/core/src/main/scala/filodb.core/query/TransientRow.scala b/core/src/main/scala/filodb.core/query/TransientRow.scala index 5d403c029b..5a0bfc5374 100644 --- a/core/src/main/scala/filodb.core/query/TransientRow.scala +++ b/core/src/main/scala/filodb.core/query/TransientRow.scala @@ -33,7 +33,7 @@ final class NaNRowReader(var timestamp: Long) extends RowReader { * IMPORTANT: It is mutable for memory efficiency purposes. Consumers from * iterators should be aware of the semantics of ability to save the next() value. */ -final class TransientRow(var timestamp: Long, var value: Double) extends MutableRowReader { +class TransientRow(var timestamp: Long, var value: Double) extends MutableRowReader { def this() = this(0L, 0d) def setValues(ts: Long, valu: Double): Unit = { @@ -194,6 +194,49 @@ final class AvgAggTransientRow extends MutableRowReader { } } +/** + * Mutable RowReader for transporting histogram average results. + * Contains three columns: Timestamp, Mean, and Count. + * Timestamp & Mean are part of the superclass, and count is added here. + */ +final class HistAvgAggTransientRow extends TransientRow { + var count: Double = 0d + + override def setLong(columnNo: Int, valu: Long): Unit = + if (columnNo == 0) timestamp = valu + else throw new IllegalArgumentException() + + override def setDouble(columnNo: Int, valu: Double): Unit = + if (columnNo == 1) super.setDouble(columnNo, valu) + else if (columnNo == 2) count = valu + else throw new IllegalArgumentException() + + override def setString(columnNo: Int, value: ZeroCopyUTF8String): Unit = throw new IllegalArgumentException() + override def setBlob(columnNo: Int, base: Array[Byte], offset: Int, length: Int): Unit = + throw new IllegalArgumentException() + override def notNull(columnNo: Int): Boolean = columnNo < 3 + override def getBoolean(columnNo: Int): Boolean = throw new IllegalArgumentException() + override def getInt(columnNo: Int): Int = throw new IllegalArgumentException() + override def getLong(columnNo: Int): Long = if (columnNo == 0) timestamp + else throw new IllegalArgumentException() + override def getDouble(columnNo: Int): Double = if (columnNo == 1) super.getDouble(columnNo) + else if (columnNo == 2) count + else throw new IllegalArgumentException() + override def getFloat(columnNo: Int): Float = throw new IllegalArgumentException() + override def getString(columnNo: Int): String = throw new IllegalArgumentException() + override def getAny(columnNo: Int): Any = throw new IllegalArgumentException() + override def getBlobBase(columnNo: Int): Any = throw new IllegalArgumentException() + override def getBlobOffset(columnNo: Int): Long = throw new IllegalArgumentException() + override def getBlobNumBytes(columnNo: Int): Int = throw new IllegalArgumentException() + + override def copyFrom(r: RowReader): Unit = r match { + case k: HistAvgAggTransientRow => + super.copyFrom(r) + count = k.count + case _ => throw new IllegalArgumentException("Unknown Row reader") + } +} + /** * Serves for stdvar and stddev * stdVal represents either stdvar or stddev diff --git a/grpc/src/main/protobuf/query_service.proto b/grpc/src/main/protobuf/query_service.proto index 0481928ec0..6619c125eb 100644 --- a/grpc/src/main/protobuf/query_service.proto +++ b/grpc/src/main/protobuf/query_service.proto @@ -459,6 +459,7 @@ enum AggregationOperator { STDVAR = 9; QUANTILE = 10; MAX = 11; + HAVG = 12; } message AggregateParameter { diff --git a/jmh/src/main/scala/filodb.jmh/Base2ExponentialHistogramQueryBenchmark.scala b/jmh/src/main/scala/filodb.jmh/Base2ExponentialHistogramQueryBenchmark.scala index eeb3b6798f..d94c0a3400 100644 --- a/jmh/src/main/scala/filodb.jmh/Base2ExponentialHistogramQueryBenchmark.scala +++ b/jmh/src/main/scala/filodb.jmh/Base2ExponentialHistogramQueryBenchmark.scala @@ -79,7 +79,7 @@ class Base2ExponentialHistogramQueryBenchmark extends StrictLogging { final val numShards = 8 final val numSamplesPerTs = 720 // 2 hours * 3600 / 10 sec interval - final val numSeries = 100 + final val numSeries = 1000 final val numQueries = 50 final val numBuckets = 160 val spread = 3 @@ -126,6 +126,17 @@ class Base2ExponentialHistogramQueryBenchmark extends StrictLogging { val queryCommands = logicalPlans.map { plan => LogicalPlan2Query(dataset.ref, plan, QueryContext(Some(new StaticSpreadProvider(SpreadChange(0, spread))), 20000)) } + + val histAvgQueryNew = """havg(rate(http_request_latency_delta{_ws_="demo", _ns_="App-0"}[5m]))""" + val histAvgQueryOld = """sum(rate(http_request_latency_delta::sum{_ws_="demo", _ns_="App-0"}[5m])) / + |sum(rate(http_request_latency_delta::count{_ws_="demo", _ns_="App-0"}[5m]))""".stripMargin + val hAvgLPOld = LogicalPlan2Query( + dataset.ref, Parser.queryRangeToLogicalPlan(histAvgQueryOld, qParams), + QueryContext(Some(new StaticSpreadProvider(SpreadChange(0, spread))), 20000)) + val hAvgLPNew = LogicalPlan2Query( + dataset.ref, Parser.queryRangeToLogicalPlan(histAvgQueryNew, qParams), + QueryContext(Some(new StaticSpreadProvider(SpreadChange(0, spread))), 20000)) + println(s"Querying data from $queryStartTime to $queryEndTime") var queriesSucceeded = 0 @@ -157,4 +168,40 @@ class Base2ExponentialHistogramQueryBenchmark extends StrictLogging { } Await.result(Future.sequence(futures), 60.seconds) } + + @Benchmark + @BenchmarkMode(Array(Mode.Throughput)) + @OutputTimeUnit(TimeUnit.SECONDS) + @OperationsPerInvocation(numQueries) + def histAvgOldQueries(): Unit = { + val futures = (0 until numQueries).map { n => + val qCmd = hAvgLPOld + val time = System.currentTimeMillis + val f = asyncAsk(coordinator, qCmd.copy(qContext = qCmd.qContext.copy(queryId = n.toString, submitTime = time))) + f.foreach { + case q: QueryResult2 => if (q.result.nonEmpty) queriesSucceeded += 1 else queryZeroResults += 1 + case e: QError => queriesFailed += 1 + } + f + } + Await.result(Future.sequence(futures), 60.seconds) + } + + @Benchmark + @BenchmarkMode(Array(Mode.Throughput)) + @OutputTimeUnit(TimeUnit.SECONDS) + @OperationsPerInvocation(numQueries) + def histAvgNewQueries(): Unit = { + val futures = (0 until numQueries).map { n => + val qCmd = hAvgLPNew + val time = System.currentTimeMillis + val f = asyncAsk(coordinator, qCmd.copy(qContext = qCmd.qContext.copy(queryId = n.toString, submitTime = time))) + f.foreach { + case q: QueryResult2 => if (q.result.nonEmpty) queriesSucceeded += 1 else queryZeroResults += 1 + case e: QError => queriesFailed += 1 + } + f + } + Await.result(Future.sequence(futures), 60.seconds) + } } diff --git a/prometheus/src/main/java/filodb/prometheus/antlr/PromQL.g4 b/prometheus/src/main/java/filodb/prometheus/antlr/PromQL.g4 index ae08e4ed1c..72c4bf5f24 100644 --- a/prometheus/src/main/java/filodb/prometheus/antlr/PromQL.g4 +++ b/prometheus/src/main/java/filodb/prometheus/antlr/PromQL.g4 @@ -184,6 +184,7 @@ AGGREGATION_OP | M I N | M A X | A V G + | H A V G | G R O U P | S T D D E V | S T D V A R diff --git a/prometheus/src/main/java/filodb/prometheus/antlr/PromQLBaseVisitor.java b/prometheus/src/main/java/filodb/prometheus/antlr/PromQLBaseVisitor.java index 8d82e55a76..fadaab8acd 100644 --- a/prometheus/src/main/java/filodb/prometheus/antlr/PromQLBaseVisitor.java +++ b/prometheus/src/main/java/filodb/prometheus/antlr/PromQLBaseVisitor.java @@ -1,4 +1,4 @@ -// Generated from PromQL.g4 by ANTLR 4.9.1 +// Generated from filodb/prometheus/antlr/PromQL.g4 by ANTLR 4.9.1 package filodb.prometheus.antlr; import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor; diff --git a/prometheus/src/main/java/filodb/prometheus/antlr/PromQLLexer.interp b/prometheus/src/main/java/filodb/prometheus/antlr/PromQLLexer.interp index 92db35ba70..7972e99267 100644 --- a/prometheus/src/main/java/filodb/prometheus/antlr/PromQLLexer.interp +++ b/prometheus/src/main/java/filodb/prometheus/antlr/PromQLLexer.interp @@ -184,4 +184,4 @@ mode names: DEFAULT_MODE atn: -[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 50, 555, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 4, 70, 9, 70, 4, 71, 9, 71, 4, 72, 9, 72, 4, 73, 9, 73, 4, 74, 9, 74, 4, 75, 9, 75, 3, 2, 3, 2, 3, 3, 3, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 10, 7, 10, 169, 10, 10, 12, 10, 14, 10, 172, 11, 10, 3, 10, 5, 10, 175, 10, 10, 3, 10, 6, 10, 178, 10, 10, 13, 10, 14, 10, 179, 3, 10, 3, 10, 5, 10, 184, 10, 10, 3, 10, 6, 10, 187, 10, 10, 13, 10, 14, 10, 188, 5, 10, 191, 10, 10, 3, 10, 6, 10, 194, 10, 10, 13, 10, 14, 10, 195, 3, 10, 3, 10, 3, 10, 3, 10, 6, 10, 202, 10, 10, 13, 10, 14, 10, 203, 5, 10, 206, 10, 10, 3, 11, 3, 11, 3, 11, 3, 11, 7, 11, 212, 10, 11, 12, 11, 14, 11, 215, 11, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 7, 11, 222, 10, 11, 12, 11, 14, 11, 225, 11, 11, 3, 11, 5, 11, 228, 10, 11, 3, 12, 5, 12, 231, 10, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 15, 3, 15, 3, 16, 3, 16, 3, 17, 3, 17, 3, 18, 3, 18, 3, 19, 3, 19, 3, 20, 3, 20, 3, 21, 3, 21, 3, 21, 3, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 24, 3, 24, 3, 25, 3, 25, 3, 25, 3, 26, 3, 26, 3, 26, 3, 27, 3, 27, 3, 27, 3, 28, 3, 28, 3, 28, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 3, 30, 3, 31, 3, 31, 3, 31, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 33, 3, 33, 3, 33, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 35, 3, 35, 3, 35, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 41, 3, 41, 3, 41, 3, 41, 3, 41, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 5, 44, 454, 10, 44, 3, 45, 3, 45, 3, 45, 6, 45, 459, 10, 45, 13, 45, 14, 45, 460, 3, 45, 3, 45, 3, 45, 5, 45, 466, 10, 45, 3, 46, 3, 46, 7, 46, 470, 10, 46, 12, 46, 14, 46, 473, 11, 46, 3, 47, 7, 47, 476, 10, 47, 12, 47, 14, 47, 479, 11, 47, 3, 47, 3, 47, 7, 47, 483, 10, 47, 12, 47, 14, 47, 486, 11, 47, 3, 48, 3, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 59, 3, 59, 3, 60, 3, 60, 3, 61, 3, 61, 3, 62, 3, 62, 3, 63, 3, 63, 3, 64, 3, 64, 3, 65, 3, 65, 3, 66, 3, 66, 3, 67, 3, 67, 3, 68, 3, 68, 3, 69, 3, 69, 3, 70, 3, 70, 3, 71, 3, 71, 3, 72, 3, 72, 3, 73, 3, 73, 3, 74, 6, 74, 541, 10, 74, 13, 74, 14, 74, 542, 3, 74, 3, 74, 3, 75, 3, 75, 7, 75, 549, 10, 75, 12, 75, 14, 75, 552, 11, 75, 3, 75, 3, 75, 2, 2, 76, 3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13, 8, 15, 9, 17, 10, 19, 11, 21, 12, 23, 13, 25, 14, 27, 15, 29, 16, 31, 17, 33, 18, 35, 19, 37, 20, 39, 21, 41, 22, 43, 23, 45, 24, 47, 25, 49, 26, 51, 27, 53, 28, 55, 29, 57, 30, 59, 31, 61, 32, 63, 33, 65, 34, 67, 35, 69, 36, 71, 37, 73, 38, 75, 39, 77, 40, 79, 41, 81, 42, 83, 43, 85, 44, 87, 45, 89, 46, 91, 47, 93, 48, 95, 2, 97, 2, 99, 2, 101, 2, 103, 2, 105, 2, 107, 2, 109, 2, 111, 2, 113, 2, 115, 2, 117, 2, 119, 2, 121, 2, 123, 2, 125, 2, 127, 2, 129, 2, 131, 2, 133, 2, 135, 2, 137, 2, 139, 2, 141, 2, 143, 2, 145, 2, 147, 49, 149, 50, 3, 2, 41, 3, 2, 50, 59, 4, 2, 71, 71, 103, 103, 4, 2, 45, 45, 47, 47, 4, 2, 90, 90, 122, 122, 5, 2, 50, 59, 67, 72, 99, 104, 4, 2, 41, 41, 94, 94, 4, 2, 36, 36, 94, 94, 8, 2, 102, 102, 106, 106, 111, 111, 117, 117, 121, 121, 123, 123, 5, 2, 67, 92, 97, 97, 99, 124, 6, 2, 50, 59, 67, 92, 97, 97, 99, 124, 4, 2, 60, 60, 97, 97, 4, 2, 67, 92, 99, 124, 7, 2, 47, 48, 50, 60, 67, 92, 97, 97, 99, 124, 4, 2, 67, 67, 99, 99, 4, 2, 68, 68, 100, 100, 4, 2, 69, 69, 101, 101, 4, 2, 70, 70, 102, 102, 4, 2, 72, 72, 104, 104, 4, 2, 73, 73, 105, 105, 4, 2, 74, 74, 106, 106, 4, 2, 75, 75, 107, 107, 4, 2, 76, 76, 108, 108, 4, 2, 77, 77, 109, 109, 4, 2, 78, 78, 110, 110, 4, 2, 79, 79, 111, 111, 4, 2, 80, 80, 112, 112, 4, 2, 81, 81, 113, 113, 4, 2, 82, 82, 114, 114, 4, 2, 83, 83, 115, 115, 4, 2, 84, 84, 116, 116, 4, 2, 85, 85, 117, 117, 4, 2, 86, 86, 118, 118, 4, 2, 87, 87, 119, 119, 4, 2, 88, 88, 120, 120, 4, 2, 89, 89, 121, 121, 4, 2, 91, 91, 123, 123, 4, 2, 92, 92, 124, 124, 5, 2, 11, 12, 15, 15, 34, 34, 4, 2, 12, 12, 15, 15, 2, 563, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2, 2, 2, 31, 3, 2, 2, 2, 2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 37, 3, 2, 2, 2, 2, 39, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 2, 47, 3, 2, 2, 2, 2, 49, 3, 2, 2, 2, 2, 51, 3, 2, 2, 2, 2, 53, 3, 2, 2, 2, 2, 55, 3, 2, 2, 2, 2, 57, 3, 2, 2, 2, 2, 59, 3, 2, 2, 2, 2, 61, 3, 2, 2, 2, 2, 63, 3, 2, 2, 2, 2, 65, 3, 2, 2, 2, 2, 67, 3, 2, 2, 2, 2, 69, 3, 2, 2, 2, 2, 71, 3, 2, 2, 2, 2, 73, 3, 2, 2, 2, 2, 75, 3, 2, 2, 2, 2, 77, 3, 2, 2, 2, 2, 79, 3, 2, 2, 2, 2, 81, 3, 2, 2, 2, 2, 83, 3, 2, 2, 2, 2, 85, 3, 2, 2, 2, 2, 87, 3, 2, 2, 2, 2, 89, 3, 2, 2, 2, 2, 91, 3, 2, 2, 2, 2, 93, 3, 2, 2, 2, 2, 147, 3, 2, 2, 2, 2, 149, 3, 2, 2, 2, 3, 151, 3, 2, 2, 2, 5, 153, 3, 2, 2, 2, 7, 155, 3, 2, 2, 2, 9, 157, 3, 2, 2, 2, 11, 159, 3, 2, 2, 2, 13, 161, 3, 2, 2, 2, 15, 163, 3, 2, 2, 2, 17, 165, 3, 2, 2, 2, 19, 205, 3, 2, 2, 2, 21, 227, 3, 2, 2, 2, 23, 230, 3, 2, 2, 2, 25, 236, 3, 2, 2, 2, 27, 240, 3, 2, 2, 2, 29, 242, 3, 2, 2, 2, 31, 244, 3, 2, 2, 2, 33, 246, 3, 2, 2, 2, 35, 248, 3, 2, 2, 2, 37, 250, 3, 2, 2, 2, 39, 252, 3, 2, 2, 2, 41, 254, 3, 2, 2, 2, 43, 257, 3, 2, 2, 2, 45, 260, 3, 2, 2, 2, 47, 262, 3, 2, 2, 2, 49, 264, 3, 2, 2, 2, 51, 267, 3, 2, 2, 2, 53, 270, 3, 2, 2, 2, 55, 273, 3, 2, 2, 2, 57, 276, 3, 2, 2, 2, 59, 278, 3, 2, 2, 2, 61, 282, 3, 2, 2, 2, 63, 285, 3, 2, 2, 2, 65, 292, 3, 2, 2, 2, 67, 295, 3, 2, 2, 2, 69, 303, 3, 2, 2, 2, 71, 306, 3, 2, 2, 2, 73, 315, 3, 2, 2, 2, 75, 326, 3, 2, 2, 2, 77, 338, 3, 2, 2, 2, 79, 345, 3, 2, 2, 2, 81, 351, 3, 2, 2, 2, 83, 356, 3, 2, 2, 2, 85, 364, 3, 2, 2, 2, 87, 453, 3, 2, 2, 2, 89, 465, 3, 2, 2, 2, 91, 467, 3, 2, 2, 2, 93, 477, 3, 2, 2, 2, 95, 487, 3, 2, 2, 2, 97, 489, 3, 2, 2, 2, 99, 491, 3, 2, 2, 2, 101, 493, 3, 2, 2, 2, 103, 495, 3, 2, 2, 2, 105, 497, 3, 2, 2, 2, 107, 499, 3, 2, 2, 2, 109, 501, 3, 2, 2, 2, 111, 503, 3, 2, 2, 2, 113, 505, 3, 2, 2, 2, 115, 507, 3, 2, 2, 2, 117, 509, 3, 2, 2, 2, 119, 511, 3, 2, 2, 2, 121, 513, 3, 2, 2, 2, 123, 515, 3, 2, 2, 2, 125, 517, 3, 2, 2, 2, 127, 519, 3, 2, 2, 2, 129, 521, 3, 2, 2, 2, 131, 523, 3, 2, 2, 2, 133, 525, 3, 2, 2, 2, 135, 527, 3, 2, 2, 2, 137, 529, 3, 2, 2, 2, 139, 531, 3, 2, 2, 2, 141, 533, 3, 2, 2, 2, 143, 535, 3, 2, 2, 2, 145, 537, 3, 2, 2, 2, 147, 540, 3, 2, 2, 2, 149, 546, 3, 2, 2, 2, 151, 152, 7, 42, 2, 2, 152, 4, 3, 2, 2, 2, 153, 154, 7, 43, 2, 2, 154, 6, 3, 2, 2, 2, 155, 156, 7, 125, 2, 2, 156, 8, 3, 2, 2, 2, 157, 158, 7, 127, 2, 2, 158, 10, 3, 2, 2, 2, 159, 160, 7, 93, 2, 2, 160, 12, 3, 2, 2, 2, 161, 162, 7, 95, 2, 2, 162, 14, 3, 2, 2, 2, 163, 164, 7, 60, 2, 2, 164, 16, 3, 2, 2, 2, 165, 166, 7, 46, 2, 2, 166, 18, 3, 2, 2, 2, 167, 169, 9, 2, 2, 2, 168, 167, 3, 2, 2, 2, 169, 172, 3, 2, 2, 2, 170, 168, 3, 2, 2, 2, 170, 171, 3, 2, 2, 2, 171, 174, 3, 2, 2, 2, 172, 170, 3, 2, 2, 2, 173, 175, 7, 48, 2, 2, 174, 173, 3, 2, 2, 2, 174, 175, 3, 2, 2, 2, 175, 177, 3, 2, 2, 2, 176, 178, 9, 2, 2, 2, 177, 176, 3, 2, 2, 2, 178, 179, 3, 2, 2, 2, 179, 177, 3, 2, 2, 2, 179, 180, 3, 2, 2, 2, 180, 190, 3, 2, 2, 2, 181, 183, 9, 3, 2, 2, 182, 184, 9, 4, 2, 2, 183, 182, 3, 2, 2, 2, 183, 184, 3, 2, 2, 2, 184, 186, 3, 2, 2, 2, 185, 187, 9, 2, 2, 2, 186, 185, 3, 2, 2, 2, 187, 188, 3, 2, 2, 2, 188, 186, 3, 2, 2, 2, 188, 189, 3, 2, 2, 2, 189, 191, 3, 2, 2, 2, 190, 181, 3, 2, 2, 2, 190, 191, 3, 2, 2, 2, 191, 206, 3, 2, 2, 2, 192, 194, 9, 2, 2, 2, 193, 192, 3, 2, 2, 2, 194, 195, 3, 2, 2, 2, 195, 193, 3, 2, 2, 2, 195, 196, 3, 2, 2, 2, 196, 197, 3, 2, 2, 2, 197, 206, 7, 48, 2, 2, 198, 199, 7, 50, 2, 2, 199, 201, 9, 5, 2, 2, 200, 202, 9, 6, 2, 2, 201, 200, 3, 2, 2, 2, 202, 203, 3, 2, 2, 2, 203, 201, 3, 2, 2, 2, 203, 204, 3, 2, 2, 2, 204, 206, 3, 2, 2, 2, 205, 170, 3, 2, 2, 2, 205, 193, 3, 2, 2, 2, 205, 198, 3, 2, 2, 2, 206, 20, 3, 2, 2, 2, 207, 213, 7, 41, 2, 2, 208, 212, 10, 7, 2, 2, 209, 210, 7, 94, 2, 2, 210, 212, 11, 2, 2, 2, 211, 208, 3, 2, 2, 2, 211, 209, 3, 2, 2, 2, 212, 215, 3, 2, 2, 2, 213, 211, 3, 2, 2, 2, 213, 214, 3, 2, 2, 2, 214, 216, 3, 2, 2, 2, 215, 213, 3, 2, 2, 2, 216, 228, 7, 41, 2, 2, 217, 223, 7, 36, 2, 2, 218, 222, 10, 8, 2, 2, 219, 220, 7, 94, 2, 2, 220, 222, 11, 2, 2, 2, 221, 218, 3, 2, 2, 2, 221, 219, 3, 2, 2, 2, 222, 225, 3, 2, 2, 2, 223, 221, 3, 2, 2, 2, 223, 224, 3, 2, 2, 2, 224, 226, 3, 2, 2, 2, 225, 223, 3, 2, 2, 2, 226, 228, 7, 36, 2, 2, 227, 207, 3, 2, 2, 2, 227, 217, 3, 2, 2, 2, 228, 22, 3, 2, 2, 2, 229, 231, 9, 4, 2, 2, 230, 229, 3, 2, 2, 2, 230, 231, 3, 2, 2, 2, 231, 232, 3, 2, 2, 2, 232, 233, 5, 111, 56, 2, 233, 234, 5, 121, 61, 2, 234, 235, 5, 105, 53, 2, 235, 24, 3, 2, 2, 2, 236, 237, 5, 121, 61, 2, 237, 238, 5, 95, 48, 2, 238, 239, 5, 121, 61, 2, 239, 26, 3, 2, 2, 2, 240, 241, 7, 45, 2, 2, 241, 28, 3, 2, 2, 2, 242, 243, 7, 47, 2, 2, 243, 30, 3, 2, 2, 2, 244, 245, 7, 44, 2, 2, 245, 32, 3, 2, 2, 2, 246, 247, 7, 49, 2, 2, 247, 34, 3, 2, 2, 2, 248, 249, 7, 39, 2, 2, 249, 36, 3, 2, 2, 2, 250, 251, 7, 96, 2, 2, 251, 38, 3, 2, 2, 2, 252, 253, 7, 63, 2, 2, 253, 40, 3, 2, 2, 2, 254, 255, 7, 63, 2, 2, 255, 256, 7, 63, 2, 2, 256, 42, 3, 2, 2, 2, 257, 258, 7, 35, 2, 2, 258, 259, 7, 63, 2, 2, 259, 44, 3, 2, 2, 2, 260, 261, 7, 64, 2, 2, 261, 46, 3, 2, 2, 2, 262, 263, 7, 62, 2, 2, 263, 48, 3, 2, 2, 2, 264, 265, 7, 64, 2, 2, 265, 266, 7, 63, 2, 2, 266, 50, 3, 2, 2, 2, 267, 268, 7, 62, 2, 2, 268, 269, 7, 63, 2, 2, 269, 52, 3, 2, 2, 2, 270, 271, 7, 63, 2, 2, 271, 272, 7, 128, 2, 2, 272, 54, 3, 2, 2, 2, 273, 274, 7, 35, 2, 2, 274, 275, 7, 128, 2, 2, 275, 56, 3, 2, 2, 2, 276, 277, 7, 66, 2, 2, 277, 58, 3, 2, 2, 2, 278, 279, 5, 95, 48, 2, 279, 280, 5, 121, 61, 2, 280, 281, 5, 101, 51, 2, 281, 60, 3, 2, 2, 2, 282, 283, 5, 123, 62, 2, 283, 284, 5, 129, 65, 2, 284, 62, 3, 2, 2, 2, 285, 286, 5, 135, 68, 2, 286, 287, 5, 121, 61, 2, 287, 288, 5, 117, 59, 2, 288, 289, 5, 103, 52, 2, 289, 290, 5, 131, 66, 2, 290, 291, 5, 131, 66, 2, 291, 64, 3, 2, 2, 2, 292, 293, 5, 97, 49, 2, 293, 294, 5, 143, 72, 2, 294, 66, 3, 2, 2, 2, 295, 296, 5, 139, 70, 2, 296, 297, 5, 111, 56, 2, 297, 298, 5, 133, 67, 2, 298, 299, 5, 109, 55, 2, 299, 300, 5, 123, 62, 2, 300, 301, 5, 135, 68, 2, 301, 302, 5, 133, 67, 2, 302, 68, 3, 2, 2, 2, 303, 304, 5, 123, 62, 2, 304, 305, 5, 121, 61, 2, 305, 70, 3, 2, 2, 2, 306, 307, 5, 111, 56, 2, 307, 308, 5, 107, 54, 2, 308, 309, 5, 121, 61, 2, 309, 310, 5, 123, 62, 2, 310, 311, 5, 129, 65, 2, 311, 312, 5, 111, 56, 2, 312, 313, 5, 121, 61, 2, 313, 314, 5, 107, 54, 2, 314, 72, 3, 2, 2, 2, 315, 316, 5, 107, 54, 2, 316, 317, 5, 129, 65, 2, 317, 318, 5, 123, 62, 2, 318, 319, 5, 135, 68, 2, 319, 320, 5, 125, 63, 2, 320, 321, 7, 97, 2, 2, 321, 322, 5, 117, 59, 2, 322, 323, 5, 103, 52, 2, 323, 324, 5, 105, 53, 2, 324, 325, 5, 133, 67, 2, 325, 74, 3, 2, 2, 2, 326, 327, 5, 107, 54, 2, 327, 328, 5, 129, 65, 2, 328, 329, 5, 123, 62, 2, 329, 330, 5, 135, 68, 2, 330, 331, 5, 125, 63, 2, 331, 332, 7, 97, 2, 2, 332, 333, 5, 129, 65, 2, 333, 334, 5, 111, 56, 2, 334, 335, 5, 107, 54, 2, 335, 336, 5, 109, 55, 2, 336, 337, 5, 133, 67, 2, 337, 76, 3, 2, 2, 2, 338, 339, 5, 123, 62, 2, 339, 340, 5, 105, 53, 2, 340, 341, 5, 105, 53, 2, 341, 342, 5, 131, 66, 2, 342, 343, 5, 103, 52, 2, 343, 344, 5, 133, 67, 2, 344, 78, 3, 2, 2, 2, 345, 346, 5, 117, 59, 2, 346, 347, 5, 111, 56, 2, 347, 348, 5, 119, 60, 2, 348, 349, 5, 111, 56, 2, 349, 350, 5, 133, 67, 2, 350, 80, 3, 2, 2, 2, 351, 352, 5, 97, 49, 2, 352, 353, 5, 123, 62, 2, 353, 354, 5, 123, 62, 2, 354, 355, 5, 117, 59, 2, 355, 82, 3, 2, 2, 2, 356, 357, 5, 131, 66, 2, 357, 358, 5, 133, 67, 2, 358, 359, 5, 95, 48, 2, 359, 360, 5, 129, 65, 2, 360, 361, 5, 133, 67, 2, 361, 362, 7, 42, 2, 2, 362, 363, 7, 43, 2, 2, 363, 84, 3, 2, 2, 2, 364, 365, 5, 103, 52, 2, 365, 366, 5, 121, 61, 2, 366, 367, 5, 101, 51, 2, 367, 368, 7, 42, 2, 2, 368, 369, 7, 43, 2, 2, 369, 86, 3, 2, 2, 2, 370, 371, 5, 131, 66, 2, 371, 372, 5, 135, 68, 2, 372, 373, 5, 119, 60, 2, 373, 454, 3, 2, 2, 2, 374, 375, 5, 119, 60, 2, 375, 376, 5, 111, 56, 2, 376, 377, 5, 121, 61, 2, 377, 454, 3, 2, 2, 2, 378, 379, 5, 119, 60, 2, 379, 380, 5, 95, 48, 2, 380, 381, 5, 141, 71, 2, 381, 454, 3, 2, 2, 2, 382, 383, 5, 95, 48, 2, 383, 384, 5, 137, 69, 2, 384, 385, 5, 107, 54, 2, 385, 454, 3, 2, 2, 2, 386, 387, 5, 107, 54, 2, 387, 388, 5, 129, 65, 2, 388, 389, 5, 123, 62, 2, 389, 390, 5, 135, 68, 2, 390, 391, 5, 125, 63, 2, 391, 454, 3, 2, 2, 2, 392, 393, 5, 131, 66, 2, 393, 394, 5, 133, 67, 2, 394, 395, 5, 101, 51, 2, 395, 396, 5, 101, 51, 2, 396, 397, 5, 103, 52, 2, 397, 398, 5, 137, 69, 2, 398, 454, 3, 2, 2, 2, 399, 400, 5, 131, 66, 2, 400, 401, 5, 133, 67, 2, 401, 402, 5, 101, 51, 2, 402, 403, 5, 137, 69, 2, 403, 404, 5, 95, 48, 2, 404, 405, 5, 129, 65, 2, 405, 454, 3, 2, 2, 2, 406, 407, 5, 99, 50, 2, 407, 408, 5, 123, 62, 2, 408, 409, 5, 135, 68, 2, 409, 410, 5, 121, 61, 2, 410, 411, 5, 133, 67, 2, 411, 454, 3, 2, 2, 2, 412, 413, 5, 99, 50, 2, 413, 414, 5, 123, 62, 2, 414, 415, 5, 135, 68, 2, 415, 416, 5, 121, 61, 2, 416, 417, 5, 133, 67, 2, 417, 418, 7, 97, 2, 2, 418, 419, 5, 137, 69, 2, 419, 420, 5, 95, 48, 2, 420, 421, 5, 117, 59, 2, 421, 422, 5, 135, 68, 2, 422, 423, 5, 103, 52, 2, 423, 424, 5, 131, 66, 2, 424, 454, 3, 2, 2, 2, 425, 426, 5, 97, 49, 2, 426, 427, 5, 123, 62, 2, 427, 428, 5, 133, 67, 2, 428, 429, 5, 133, 67, 2, 429, 430, 5, 123, 62, 2, 430, 431, 5, 119, 60, 2, 431, 432, 5, 115, 58, 2, 432, 454, 3, 2, 2, 2, 433, 434, 5, 133, 67, 2, 434, 435, 5, 123, 62, 2, 435, 436, 5, 125, 63, 2, 436, 437, 5, 115, 58, 2, 437, 454, 3, 2, 2, 2, 438, 439, 5, 127, 64, 2, 439, 440, 5, 135, 68, 2, 440, 441, 5, 95, 48, 2, 441, 442, 5, 121, 61, 2, 442, 443, 5, 133, 67, 2, 443, 444, 5, 111, 56, 2, 444, 445, 5, 117, 59, 2, 445, 446, 5, 103, 52, 2, 446, 454, 3, 2, 2, 2, 447, 448, 5, 107, 54, 2, 448, 449, 5, 129, 65, 2, 449, 450, 5, 123, 62, 2, 450, 451, 5, 135, 68, 2, 451, 452, 5, 125, 63, 2, 452, 454, 3, 2, 2, 2, 453, 370, 3, 2, 2, 2, 453, 374, 3, 2, 2, 2, 453, 378, 3, 2, 2, 2, 453, 382, 3, 2, 2, 2, 453, 386, 3, 2, 2, 2, 453, 392, 3, 2, 2, 2, 453, 399, 3, 2, 2, 2, 453, 406, 3, 2, 2, 2, 453, 412, 3, 2, 2, 2, 453, 425, 3, 2, 2, 2, 453, 433, 3, 2, 2, 2, 453, 438, 3, 2, 2, 2, 453, 447, 3, 2, 2, 2, 454, 88, 3, 2, 2, 2, 455, 456, 5, 19, 10, 2, 456, 457, 9, 9, 2, 2, 457, 459, 3, 2, 2, 2, 458, 455, 3, 2, 2, 2, 459, 460, 3, 2, 2, 2, 460, 458, 3, 2, 2, 2, 460, 461, 3, 2, 2, 2, 461, 466, 3, 2, 2, 2, 462, 463, 5, 19, 10, 2, 463, 464, 7, 107, 2, 2, 464, 466, 3, 2, 2, 2, 465, 458, 3, 2, 2, 2, 465, 462, 3, 2, 2, 2, 466, 90, 3, 2, 2, 2, 467, 471, 9, 10, 2, 2, 468, 470, 9, 11, 2, 2, 469, 468, 3, 2, 2, 2, 470, 473, 3, 2, 2, 2, 471, 469, 3, 2, 2, 2, 471, 472, 3, 2, 2, 2, 472, 92, 3, 2, 2, 2, 473, 471, 3, 2, 2, 2, 474, 476, 9, 12, 2, 2, 475, 474, 3, 2, 2, 2, 476, 479, 3, 2, 2, 2, 477, 475, 3, 2, 2, 2, 477, 478, 3, 2, 2, 2, 478, 480, 3, 2, 2, 2, 479, 477, 3, 2, 2, 2, 480, 484, 9, 13, 2, 2, 481, 483, 9, 14, 2, 2, 482, 481, 3, 2, 2, 2, 483, 486, 3, 2, 2, 2, 484, 482, 3, 2, 2, 2, 484, 485, 3, 2, 2, 2, 485, 94, 3, 2, 2, 2, 486, 484, 3, 2, 2, 2, 487, 488, 9, 15, 2, 2, 488, 96, 3, 2, 2, 2, 489, 490, 9, 16, 2, 2, 490, 98, 3, 2, 2, 2, 491, 492, 9, 17, 2, 2, 492, 100, 3, 2, 2, 2, 493, 494, 9, 18, 2, 2, 494, 102, 3, 2, 2, 2, 495, 496, 9, 3, 2, 2, 496, 104, 3, 2, 2, 2, 497, 498, 9, 19, 2, 2, 498, 106, 3, 2, 2, 2, 499, 500, 9, 20, 2, 2, 500, 108, 3, 2, 2, 2, 501, 502, 9, 21, 2, 2, 502, 110, 3, 2, 2, 2, 503, 504, 9, 22, 2, 2, 504, 112, 3, 2, 2, 2, 505, 506, 9, 23, 2, 2, 506, 114, 3, 2, 2, 2, 507, 508, 9, 24, 2, 2, 508, 116, 3, 2, 2, 2, 509, 510, 9, 25, 2, 2, 510, 118, 3, 2, 2, 2, 511, 512, 9, 26, 2, 2, 512, 120, 3, 2, 2, 2, 513, 514, 9, 27, 2, 2, 514, 122, 3, 2, 2, 2, 515, 516, 9, 28, 2, 2, 516, 124, 3, 2, 2, 2, 517, 518, 9, 29, 2, 2, 518, 126, 3, 2, 2, 2, 519, 520, 9, 30, 2, 2, 520, 128, 3, 2, 2, 2, 521, 522, 9, 31, 2, 2, 522, 130, 3, 2, 2, 2, 523, 524, 9, 32, 2, 2, 524, 132, 3, 2, 2, 2, 525, 526, 9, 33, 2, 2, 526, 134, 3, 2, 2, 2, 527, 528, 9, 34, 2, 2, 528, 136, 3, 2, 2, 2, 529, 530, 9, 35, 2, 2, 530, 138, 3, 2, 2, 2, 531, 532, 9, 36, 2, 2, 532, 140, 3, 2, 2, 2, 533, 534, 9, 5, 2, 2, 534, 142, 3, 2, 2, 2, 535, 536, 9, 37, 2, 2, 536, 144, 3, 2, 2, 2, 537, 538, 9, 38, 2, 2, 538, 146, 3, 2, 2, 2, 539, 541, 9, 39, 2, 2, 540, 539, 3, 2, 2, 2, 541, 542, 3, 2, 2, 2, 542, 540, 3, 2, 2, 2, 542, 543, 3, 2, 2, 2, 543, 544, 3, 2, 2, 2, 544, 545, 8, 74, 2, 2, 545, 148, 3, 2, 2, 2, 546, 550, 7, 37, 2, 2, 547, 549, 10, 40, 2, 2, 548, 547, 3, 2, 2, 2, 549, 552, 3, 2, 2, 2, 550, 548, 3, 2, 2, 2, 550, 551, 3, 2, 2, 2, 551, 553, 3, 2, 2, 2, 552, 550, 3, 2, 2, 2, 553, 554, 8, 75, 2, 2, 554, 150, 3, 2, 2, 2, 26, 2, 170, 174, 179, 183, 188, 190, 195, 203, 205, 211, 213, 221, 223, 227, 230, 453, 460, 465, 471, 477, 484, 542, 550, 3, 8, 2, 2] \ No newline at end of file +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 50, 560, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 4, 70, 9, 70, 4, 71, 9, 71, 4, 72, 9, 72, 4, 73, 9, 73, 4, 74, 9, 74, 4, 75, 9, 75, 3, 2, 3, 2, 3, 3, 3, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 10, 7, 10, 169, 10, 10, 12, 10, 14, 10, 172, 11, 10, 3, 10, 5, 10, 175, 10, 10, 3, 10, 6, 10, 178, 10, 10, 13, 10, 14, 10, 179, 3, 10, 3, 10, 5, 10, 184, 10, 10, 3, 10, 6, 10, 187, 10, 10, 13, 10, 14, 10, 188, 5, 10, 191, 10, 10, 3, 10, 6, 10, 194, 10, 10, 13, 10, 14, 10, 195, 3, 10, 3, 10, 3, 10, 3, 10, 6, 10, 202, 10, 10, 13, 10, 14, 10, 203, 5, 10, 206, 10, 10, 3, 11, 3, 11, 3, 11, 3, 11, 7, 11, 212, 10, 11, 12, 11, 14, 11, 215, 11, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 7, 11, 222, 10, 11, 12, 11, 14, 11, 225, 11, 11, 3, 11, 5, 11, 228, 10, 11, 3, 12, 5, 12, 231, 10, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 15, 3, 15, 3, 16, 3, 16, 3, 17, 3, 17, 3, 18, 3, 18, 3, 19, 3, 19, 3, 20, 3, 20, 3, 21, 3, 21, 3, 21, 3, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 24, 3, 24, 3, 25, 3, 25, 3, 25, 3, 26, 3, 26, 3, 26, 3, 27, 3, 27, 3, 27, 3, 28, 3, 28, 3, 28, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 3, 30, 3, 31, 3, 31, 3, 31, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 33, 3, 33, 3, 33, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 35, 3, 35, 3, 35, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 41, 3, 41, 3, 41, 3, 41, 3, 41, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 5, 44, 459, 10, 44, 3, 45, 3, 45, 3, 45, 6, 45, 464, 10, 45, 13, 45, 14, 45, 465, 3, 45, 3, 45, 3, 45, 5, 45, 471, 10, 45, 3, 46, 3, 46, 7, 46, 475, 10, 46, 12, 46, 14, 46, 478, 11, 46, 3, 47, 7, 47, 481, 10, 47, 12, 47, 14, 47, 484, 11, 47, 3, 47, 3, 47, 7, 47, 488, 10, 47, 12, 47, 14, 47, 491, 11, 47, 3, 48, 3, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 59, 3, 59, 3, 60, 3, 60, 3, 61, 3, 61, 3, 62, 3, 62, 3, 63, 3, 63, 3, 64, 3, 64, 3, 65, 3, 65, 3, 66, 3, 66, 3, 67, 3, 67, 3, 68, 3, 68, 3, 69, 3, 69, 3, 70, 3, 70, 3, 71, 3, 71, 3, 72, 3, 72, 3, 73, 3, 73, 3, 74, 6, 74, 546, 10, 74, 13, 74, 14, 74, 547, 3, 74, 3, 74, 3, 75, 3, 75, 7, 75, 554, 10, 75, 12, 75, 14, 75, 557, 11, 75, 3, 75, 3, 75, 2, 2, 76, 3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13, 8, 15, 9, 17, 10, 19, 11, 21, 12, 23, 13, 25, 14, 27, 15, 29, 16, 31, 17, 33, 18, 35, 19, 37, 20, 39, 21, 41, 22, 43, 23, 45, 24, 47, 25, 49, 26, 51, 27, 53, 28, 55, 29, 57, 30, 59, 31, 61, 32, 63, 33, 65, 34, 67, 35, 69, 36, 71, 37, 73, 38, 75, 39, 77, 40, 79, 41, 81, 42, 83, 43, 85, 44, 87, 45, 89, 46, 91, 47, 93, 48, 95, 2, 97, 2, 99, 2, 101, 2, 103, 2, 105, 2, 107, 2, 109, 2, 111, 2, 113, 2, 115, 2, 117, 2, 119, 2, 121, 2, 123, 2, 125, 2, 127, 2, 129, 2, 131, 2, 133, 2, 135, 2, 137, 2, 139, 2, 141, 2, 143, 2, 145, 2, 147, 49, 149, 50, 3, 2, 41, 3, 2, 50, 59, 4, 2, 71, 71, 103, 103, 4, 2, 45, 45, 47, 47, 4, 2, 90, 90, 122, 122, 5, 2, 50, 59, 67, 72, 99, 104, 4, 2, 41, 41, 94, 94, 4, 2, 36, 36, 94, 94, 8, 2, 102, 102, 106, 106, 111, 111, 117, 117, 121, 121, 123, 123, 5, 2, 67, 92, 97, 97, 99, 124, 6, 2, 50, 59, 67, 92, 97, 97, 99, 124, 4, 2, 60, 60, 97, 97, 4, 2, 67, 92, 99, 124, 7, 2, 47, 48, 50, 60, 67, 92, 97, 97, 99, 124, 4, 2, 67, 67, 99, 99, 4, 2, 68, 68, 100, 100, 4, 2, 69, 69, 101, 101, 4, 2, 70, 70, 102, 102, 4, 2, 72, 72, 104, 104, 4, 2, 73, 73, 105, 105, 4, 2, 74, 74, 106, 106, 4, 2, 75, 75, 107, 107, 4, 2, 76, 76, 108, 108, 4, 2, 77, 77, 109, 109, 4, 2, 78, 78, 110, 110, 4, 2, 79, 79, 111, 111, 4, 2, 80, 80, 112, 112, 4, 2, 81, 81, 113, 113, 4, 2, 82, 82, 114, 114, 4, 2, 83, 83, 115, 115, 4, 2, 84, 84, 116, 116, 4, 2, 85, 85, 117, 117, 4, 2, 86, 86, 118, 118, 4, 2, 87, 87, 119, 119, 4, 2, 88, 88, 120, 120, 4, 2, 89, 89, 121, 121, 4, 2, 91, 91, 123, 123, 4, 2, 92, 92, 124, 124, 5, 2, 11, 12, 15, 15, 34, 34, 4, 2, 12, 12, 15, 15, 2, 569, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2, 2, 2, 31, 3, 2, 2, 2, 2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 37, 3, 2, 2, 2, 2, 39, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 2, 47, 3, 2, 2, 2, 2, 49, 3, 2, 2, 2, 2, 51, 3, 2, 2, 2, 2, 53, 3, 2, 2, 2, 2, 55, 3, 2, 2, 2, 2, 57, 3, 2, 2, 2, 2, 59, 3, 2, 2, 2, 2, 61, 3, 2, 2, 2, 2, 63, 3, 2, 2, 2, 2, 65, 3, 2, 2, 2, 2, 67, 3, 2, 2, 2, 2, 69, 3, 2, 2, 2, 2, 71, 3, 2, 2, 2, 2, 73, 3, 2, 2, 2, 2, 75, 3, 2, 2, 2, 2, 77, 3, 2, 2, 2, 2, 79, 3, 2, 2, 2, 2, 81, 3, 2, 2, 2, 2, 83, 3, 2, 2, 2, 2, 85, 3, 2, 2, 2, 2, 87, 3, 2, 2, 2, 2, 89, 3, 2, 2, 2, 2, 91, 3, 2, 2, 2, 2, 93, 3, 2, 2, 2, 2, 147, 3, 2, 2, 2, 2, 149, 3, 2, 2, 2, 3, 151, 3, 2, 2, 2, 5, 153, 3, 2, 2, 2, 7, 155, 3, 2, 2, 2, 9, 157, 3, 2, 2, 2, 11, 159, 3, 2, 2, 2, 13, 161, 3, 2, 2, 2, 15, 163, 3, 2, 2, 2, 17, 165, 3, 2, 2, 2, 19, 205, 3, 2, 2, 2, 21, 227, 3, 2, 2, 2, 23, 230, 3, 2, 2, 2, 25, 236, 3, 2, 2, 2, 27, 240, 3, 2, 2, 2, 29, 242, 3, 2, 2, 2, 31, 244, 3, 2, 2, 2, 33, 246, 3, 2, 2, 2, 35, 248, 3, 2, 2, 2, 37, 250, 3, 2, 2, 2, 39, 252, 3, 2, 2, 2, 41, 254, 3, 2, 2, 2, 43, 257, 3, 2, 2, 2, 45, 260, 3, 2, 2, 2, 47, 262, 3, 2, 2, 2, 49, 264, 3, 2, 2, 2, 51, 267, 3, 2, 2, 2, 53, 270, 3, 2, 2, 2, 55, 273, 3, 2, 2, 2, 57, 276, 3, 2, 2, 2, 59, 278, 3, 2, 2, 2, 61, 282, 3, 2, 2, 2, 63, 285, 3, 2, 2, 2, 65, 292, 3, 2, 2, 2, 67, 295, 3, 2, 2, 2, 69, 303, 3, 2, 2, 2, 71, 306, 3, 2, 2, 2, 73, 315, 3, 2, 2, 2, 75, 326, 3, 2, 2, 2, 77, 338, 3, 2, 2, 2, 79, 345, 3, 2, 2, 2, 81, 351, 3, 2, 2, 2, 83, 356, 3, 2, 2, 2, 85, 364, 3, 2, 2, 2, 87, 458, 3, 2, 2, 2, 89, 470, 3, 2, 2, 2, 91, 472, 3, 2, 2, 2, 93, 482, 3, 2, 2, 2, 95, 492, 3, 2, 2, 2, 97, 494, 3, 2, 2, 2, 99, 496, 3, 2, 2, 2, 101, 498, 3, 2, 2, 2, 103, 500, 3, 2, 2, 2, 105, 502, 3, 2, 2, 2, 107, 504, 3, 2, 2, 2, 109, 506, 3, 2, 2, 2, 111, 508, 3, 2, 2, 2, 113, 510, 3, 2, 2, 2, 115, 512, 3, 2, 2, 2, 117, 514, 3, 2, 2, 2, 119, 516, 3, 2, 2, 2, 121, 518, 3, 2, 2, 2, 123, 520, 3, 2, 2, 2, 125, 522, 3, 2, 2, 2, 127, 524, 3, 2, 2, 2, 129, 526, 3, 2, 2, 2, 131, 528, 3, 2, 2, 2, 133, 530, 3, 2, 2, 2, 135, 532, 3, 2, 2, 2, 137, 534, 3, 2, 2, 2, 139, 536, 3, 2, 2, 2, 141, 538, 3, 2, 2, 2, 143, 540, 3, 2, 2, 2, 145, 542, 3, 2, 2, 2, 147, 545, 3, 2, 2, 2, 149, 551, 3, 2, 2, 2, 151, 152, 7, 42, 2, 2, 152, 4, 3, 2, 2, 2, 153, 154, 7, 43, 2, 2, 154, 6, 3, 2, 2, 2, 155, 156, 7, 125, 2, 2, 156, 8, 3, 2, 2, 2, 157, 158, 7, 127, 2, 2, 158, 10, 3, 2, 2, 2, 159, 160, 7, 93, 2, 2, 160, 12, 3, 2, 2, 2, 161, 162, 7, 95, 2, 2, 162, 14, 3, 2, 2, 2, 163, 164, 7, 60, 2, 2, 164, 16, 3, 2, 2, 2, 165, 166, 7, 46, 2, 2, 166, 18, 3, 2, 2, 2, 167, 169, 9, 2, 2, 2, 168, 167, 3, 2, 2, 2, 169, 172, 3, 2, 2, 2, 170, 168, 3, 2, 2, 2, 170, 171, 3, 2, 2, 2, 171, 174, 3, 2, 2, 2, 172, 170, 3, 2, 2, 2, 173, 175, 7, 48, 2, 2, 174, 173, 3, 2, 2, 2, 174, 175, 3, 2, 2, 2, 175, 177, 3, 2, 2, 2, 176, 178, 9, 2, 2, 2, 177, 176, 3, 2, 2, 2, 178, 179, 3, 2, 2, 2, 179, 177, 3, 2, 2, 2, 179, 180, 3, 2, 2, 2, 180, 190, 3, 2, 2, 2, 181, 183, 9, 3, 2, 2, 182, 184, 9, 4, 2, 2, 183, 182, 3, 2, 2, 2, 183, 184, 3, 2, 2, 2, 184, 186, 3, 2, 2, 2, 185, 187, 9, 2, 2, 2, 186, 185, 3, 2, 2, 2, 187, 188, 3, 2, 2, 2, 188, 186, 3, 2, 2, 2, 188, 189, 3, 2, 2, 2, 189, 191, 3, 2, 2, 2, 190, 181, 3, 2, 2, 2, 190, 191, 3, 2, 2, 2, 191, 206, 3, 2, 2, 2, 192, 194, 9, 2, 2, 2, 193, 192, 3, 2, 2, 2, 194, 195, 3, 2, 2, 2, 195, 193, 3, 2, 2, 2, 195, 196, 3, 2, 2, 2, 196, 197, 3, 2, 2, 2, 197, 206, 7, 48, 2, 2, 198, 199, 7, 50, 2, 2, 199, 201, 9, 5, 2, 2, 200, 202, 9, 6, 2, 2, 201, 200, 3, 2, 2, 2, 202, 203, 3, 2, 2, 2, 203, 201, 3, 2, 2, 2, 203, 204, 3, 2, 2, 2, 204, 206, 3, 2, 2, 2, 205, 170, 3, 2, 2, 2, 205, 193, 3, 2, 2, 2, 205, 198, 3, 2, 2, 2, 206, 20, 3, 2, 2, 2, 207, 213, 7, 41, 2, 2, 208, 212, 10, 7, 2, 2, 209, 210, 7, 94, 2, 2, 210, 212, 11, 2, 2, 2, 211, 208, 3, 2, 2, 2, 211, 209, 3, 2, 2, 2, 212, 215, 3, 2, 2, 2, 213, 211, 3, 2, 2, 2, 213, 214, 3, 2, 2, 2, 214, 216, 3, 2, 2, 2, 215, 213, 3, 2, 2, 2, 216, 228, 7, 41, 2, 2, 217, 223, 7, 36, 2, 2, 218, 222, 10, 8, 2, 2, 219, 220, 7, 94, 2, 2, 220, 222, 11, 2, 2, 2, 221, 218, 3, 2, 2, 2, 221, 219, 3, 2, 2, 2, 222, 225, 3, 2, 2, 2, 223, 221, 3, 2, 2, 2, 223, 224, 3, 2, 2, 2, 224, 226, 3, 2, 2, 2, 225, 223, 3, 2, 2, 2, 226, 228, 7, 36, 2, 2, 227, 207, 3, 2, 2, 2, 227, 217, 3, 2, 2, 2, 228, 22, 3, 2, 2, 2, 229, 231, 9, 4, 2, 2, 230, 229, 3, 2, 2, 2, 230, 231, 3, 2, 2, 2, 231, 232, 3, 2, 2, 2, 232, 233, 5, 111, 56, 2, 233, 234, 5, 121, 61, 2, 234, 235, 5, 105, 53, 2, 235, 24, 3, 2, 2, 2, 236, 237, 5, 121, 61, 2, 237, 238, 5, 95, 48, 2, 238, 239, 5, 121, 61, 2, 239, 26, 3, 2, 2, 2, 240, 241, 7, 45, 2, 2, 241, 28, 3, 2, 2, 2, 242, 243, 7, 47, 2, 2, 243, 30, 3, 2, 2, 2, 244, 245, 7, 44, 2, 2, 245, 32, 3, 2, 2, 2, 246, 247, 7, 49, 2, 2, 247, 34, 3, 2, 2, 2, 248, 249, 7, 39, 2, 2, 249, 36, 3, 2, 2, 2, 250, 251, 7, 96, 2, 2, 251, 38, 3, 2, 2, 2, 252, 253, 7, 63, 2, 2, 253, 40, 3, 2, 2, 2, 254, 255, 7, 63, 2, 2, 255, 256, 7, 63, 2, 2, 256, 42, 3, 2, 2, 2, 257, 258, 7, 35, 2, 2, 258, 259, 7, 63, 2, 2, 259, 44, 3, 2, 2, 2, 260, 261, 7, 64, 2, 2, 261, 46, 3, 2, 2, 2, 262, 263, 7, 62, 2, 2, 263, 48, 3, 2, 2, 2, 264, 265, 7, 64, 2, 2, 265, 266, 7, 63, 2, 2, 266, 50, 3, 2, 2, 2, 267, 268, 7, 62, 2, 2, 268, 269, 7, 63, 2, 2, 269, 52, 3, 2, 2, 2, 270, 271, 7, 63, 2, 2, 271, 272, 7, 128, 2, 2, 272, 54, 3, 2, 2, 2, 273, 274, 7, 35, 2, 2, 274, 275, 7, 128, 2, 2, 275, 56, 3, 2, 2, 2, 276, 277, 7, 66, 2, 2, 277, 58, 3, 2, 2, 2, 278, 279, 5, 95, 48, 2, 279, 280, 5, 121, 61, 2, 280, 281, 5, 101, 51, 2, 281, 60, 3, 2, 2, 2, 282, 283, 5, 123, 62, 2, 283, 284, 5, 129, 65, 2, 284, 62, 3, 2, 2, 2, 285, 286, 5, 135, 68, 2, 286, 287, 5, 121, 61, 2, 287, 288, 5, 117, 59, 2, 288, 289, 5, 103, 52, 2, 289, 290, 5, 131, 66, 2, 290, 291, 5, 131, 66, 2, 291, 64, 3, 2, 2, 2, 292, 293, 5, 97, 49, 2, 293, 294, 5, 143, 72, 2, 294, 66, 3, 2, 2, 2, 295, 296, 5, 139, 70, 2, 296, 297, 5, 111, 56, 2, 297, 298, 5, 133, 67, 2, 298, 299, 5, 109, 55, 2, 299, 300, 5, 123, 62, 2, 300, 301, 5, 135, 68, 2, 301, 302, 5, 133, 67, 2, 302, 68, 3, 2, 2, 2, 303, 304, 5, 123, 62, 2, 304, 305, 5, 121, 61, 2, 305, 70, 3, 2, 2, 2, 306, 307, 5, 111, 56, 2, 307, 308, 5, 107, 54, 2, 308, 309, 5, 121, 61, 2, 309, 310, 5, 123, 62, 2, 310, 311, 5, 129, 65, 2, 311, 312, 5, 111, 56, 2, 312, 313, 5, 121, 61, 2, 313, 314, 5, 107, 54, 2, 314, 72, 3, 2, 2, 2, 315, 316, 5, 107, 54, 2, 316, 317, 5, 129, 65, 2, 317, 318, 5, 123, 62, 2, 318, 319, 5, 135, 68, 2, 319, 320, 5, 125, 63, 2, 320, 321, 7, 97, 2, 2, 321, 322, 5, 117, 59, 2, 322, 323, 5, 103, 52, 2, 323, 324, 5, 105, 53, 2, 324, 325, 5, 133, 67, 2, 325, 74, 3, 2, 2, 2, 326, 327, 5, 107, 54, 2, 327, 328, 5, 129, 65, 2, 328, 329, 5, 123, 62, 2, 329, 330, 5, 135, 68, 2, 330, 331, 5, 125, 63, 2, 331, 332, 7, 97, 2, 2, 332, 333, 5, 129, 65, 2, 333, 334, 5, 111, 56, 2, 334, 335, 5, 107, 54, 2, 335, 336, 5, 109, 55, 2, 336, 337, 5, 133, 67, 2, 337, 76, 3, 2, 2, 2, 338, 339, 5, 123, 62, 2, 339, 340, 5, 105, 53, 2, 340, 341, 5, 105, 53, 2, 341, 342, 5, 131, 66, 2, 342, 343, 5, 103, 52, 2, 343, 344, 5, 133, 67, 2, 344, 78, 3, 2, 2, 2, 345, 346, 5, 117, 59, 2, 346, 347, 5, 111, 56, 2, 347, 348, 5, 119, 60, 2, 348, 349, 5, 111, 56, 2, 349, 350, 5, 133, 67, 2, 350, 80, 3, 2, 2, 2, 351, 352, 5, 97, 49, 2, 352, 353, 5, 123, 62, 2, 353, 354, 5, 123, 62, 2, 354, 355, 5, 117, 59, 2, 355, 82, 3, 2, 2, 2, 356, 357, 5, 131, 66, 2, 357, 358, 5, 133, 67, 2, 358, 359, 5, 95, 48, 2, 359, 360, 5, 129, 65, 2, 360, 361, 5, 133, 67, 2, 361, 362, 7, 42, 2, 2, 362, 363, 7, 43, 2, 2, 363, 84, 3, 2, 2, 2, 364, 365, 5, 103, 52, 2, 365, 366, 5, 121, 61, 2, 366, 367, 5, 101, 51, 2, 367, 368, 7, 42, 2, 2, 368, 369, 7, 43, 2, 2, 369, 86, 3, 2, 2, 2, 370, 371, 5, 131, 66, 2, 371, 372, 5, 135, 68, 2, 372, 373, 5, 119, 60, 2, 373, 459, 3, 2, 2, 2, 374, 375, 5, 119, 60, 2, 375, 376, 5, 111, 56, 2, 376, 377, 5, 121, 61, 2, 377, 459, 3, 2, 2, 2, 378, 379, 5, 119, 60, 2, 379, 380, 5, 95, 48, 2, 380, 381, 5, 141, 71, 2, 381, 459, 3, 2, 2, 2, 382, 383, 5, 95, 48, 2, 383, 384, 5, 137, 69, 2, 384, 385, 5, 107, 54, 2, 385, 459, 3, 2, 2, 2, 386, 387, 5, 109, 55, 2, 387, 388, 5, 95, 48, 2, 388, 389, 5, 137, 69, 2, 389, 390, 5, 107, 54, 2, 390, 459, 3, 2, 2, 2, 391, 392, 5, 107, 54, 2, 392, 393, 5, 129, 65, 2, 393, 394, 5, 123, 62, 2, 394, 395, 5, 135, 68, 2, 395, 396, 5, 125, 63, 2, 396, 459, 3, 2, 2, 2, 397, 398, 5, 131, 66, 2, 398, 399, 5, 133, 67, 2, 399, 400, 5, 101, 51, 2, 400, 401, 5, 101, 51, 2, 401, 402, 5, 103, 52, 2, 402, 403, 5, 137, 69, 2, 403, 459, 3, 2, 2, 2, 404, 405, 5, 131, 66, 2, 405, 406, 5, 133, 67, 2, 406, 407, 5, 101, 51, 2, 407, 408, 5, 137, 69, 2, 408, 409, 5, 95, 48, 2, 409, 410, 5, 129, 65, 2, 410, 459, 3, 2, 2, 2, 411, 412, 5, 99, 50, 2, 412, 413, 5, 123, 62, 2, 413, 414, 5, 135, 68, 2, 414, 415, 5, 121, 61, 2, 415, 416, 5, 133, 67, 2, 416, 459, 3, 2, 2, 2, 417, 418, 5, 99, 50, 2, 418, 419, 5, 123, 62, 2, 419, 420, 5, 135, 68, 2, 420, 421, 5, 121, 61, 2, 421, 422, 5, 133, 67, 2, 422, 423, 7, 97, 2, 2, 423, 424, 5, 137, 69, 2, 424, 425, 5, 95, 48, 2, 425, 426, 5, 117, 59, 2, 426, 427, 5, 135, 68, 2, 427, 428, 5, 103, 52, 2, 428, 429, 5, 131, 66, 2, 429, 459, 3, 2, 2, 2, 430, 431, 5, 97, 49, 2, 431, 432, 5, 123, 62, 2, 432, 433, 5, 133, 67, 2, 433, 434, 5, 133, 67, 2, 434, 435, 5, 123, 62, 2, 435, 436, 5, 119, 60, 2, 436, 437, 5, 115, 58, 2, 437, 459, 3, 2, 2, 2, 438, 439, 5, 133, 67, 2, 439, 440, 5, 123, 62, 2, 440, 441, 5, 125, 63, 2, 441, 442, 5, 115, 58, 2, 442, 459, 3, 2, 2, 2, 443, 444, 5, 127, 64, 2, 444, 445, 5, 135, 68, 2, 445, 446, 5, 95, 48, 2, 446, 447, 5, 121, 61, 2, 447, 448, 5, 133, 67, 2, 448, 449, 5, 111, 56, 2, 449, 450, 5, 117, 59, 2, 450, 451, 5, 103, 52, 2, 451, 459, 3, 2, 2, 2, 452, 453, 5, 107, 54, 2, 453, 454, 5, 129, 65, 2, 454, 455, 5, 123, 62, 2, 455, 456, 5, 135, 68, 2, 456, 457, 5, 125, 63, 2, 457, 459, 3, 2, 2, 2, 458, 370, 3, 2, 2, 2, 458, 374, 3, 2, 2, 2, 458, 378, 3, 2, 2, 2, 458, 382, 3, 2, 2, 2, 458, 386, 3, 2, 2, 2, 458, 391, 3, 2, 2, 2, 458, 397, 3, 2, 2, 2, 458, 404, 3, 2, 2, 2, 458, 411, 3, 2, 2, 2, 458, 417, 3, 2, 2, 2, 458, 430, 3, 2, 2, 2, 458, 438, 3, 2, 2, 2, 458, 443, 3, 2, 2, 2, 458, 452, 3, 2, 2, 2, 459, 88, 3, 2, 2, 2, 460, 461, 5, 19, 10, 2, 461, 462, 9, 9, 2, 2, 462, 464, 3, 2, 2, 2, 463, 460, 3, 2, 2, 2, 464, 465, 3, 2, 2, 2, 465, 463, 3, 2, 2, 2, 465, 466, 3, 2, 2, 2, 466, 471, 3, 2, 2, 2, 467, 468, 5, 19, 10, 2, 468, 469, 7, 107, 2, 2, 469, 471, 3, 2, 2, 2, 470, 463, 3, 2, 2, 2, 470, 467, 3, 2, 2, 2, 471, 90, 3, 2, 2, 2, 472, 476, 9, 10, 2, 2, 473, 475, 9, 11, 2, 2, 474, 473, 3, 2, 2, 2, 475, 478, 3, 2, 2, 2, 476, 474, 3, 2, 2, 2, 476, 477, 3, 2, 2, 2, 477, 92, 3, 2, 2, 2, 478, 476, 3, 2, 2, 2, 479, 481, 9, 12, 2, 2, 480, 479, 3, 2, 2, 2, 481, 484, 3, 2, 2, 2, 482, 480, 3, 2, 2, 2, 482, 483, 3, 2, 2, 2, 483, 485, 3, 2, 2, 2, 484, 482, 3, 2, 2, 2, 485, 489, 9, 13, 2, 2, 486, 488, 9, 14, 2, 2, 487, 486, 3, 2, 2, 2, 488, 491, 3, 2, 2, 2, 489, 487, 3, 2, 2, 2, 489, 490, 3, 2, 2, 2, 490, 94, 3, 2, 2, 2, 491, 489, 3, 2, 2, 2, 492, 493, 9, 15, 2, 2, 493, 96, 3, 2, 2, 2, 494, 495, 9, 16, 2, 2, 495, 98, 3, 2, 2, 2, 496, 497, 9, 17, 2, 2, 497, 100, 3, 2, 2, 2, 498, 499, 9, 18, 2, 2, 499, 102, 3, 2, 2, 2, 500, 501, 9, 3, 2, 2, 501, 104, 3, 2, 2, 2, 502, 503, 9, 19, 2, 2, 503, 106, 3, 2, 2, 2, 504, 505, 9, 20, 2, 2, 505, 108, 3, 2, 2, 2, 506, 507, 9, 21, 2, 2, 507, 110, 3, 2, 2, 2, 508, 509, 9, 22, 2, 2, 509, 112, 3, 2, 2, 2, 510, 511, 9, 23, 2, 2, 511, 114, 3, 2, 2, 2, 512, 513, 9, 24, 2, 2, 513, 116, 3, 2, 2, 2, 514, 515, 9, 25, 2, 2, 515, 118, 3, 2, 2, 2, 516, 517, 9, 26, 2, 2, 517, 120, 3, 2, 2, 2, 518, 519, 9, 27, 2, 2, 519, 122, 3, 2, 2, 2, 520, 521, 9, 28, 2, 2, 521, 124, 3, 2, 2, 2, 522, 523, 9, 29, 2, 2, 523, 126, 3, 2, 2, 2, 524, 525, 9, 30, 2, 2, 525, 128, 3, 2, 2, 2, 526, 527, 9, 31, 2, 2, 527, 130, 3, 2, 2, 2, 528, 529, 9, 32, 2, 2, 529, 132, 3, 2, 2, 2, 530, 531, 9, 33, 2, 2, 531, 134, 3, 2, 2, 2, 532, 533, 9, 34, 2, 2, 533, 136, 3, 2, 2, 2, 534, 535, 9, 35, 2, 2, 535, 138, 3, 2, 2, 2, 536, 537, 9, 36, 2, 2, 537, 140, 3, 2, 2, 2, 538, 539, 9, 5, 2, 2, 539, 142, 3, 2, 2, 2, 540, 541, 9, 37, 2, 2, 541, 144, 3, 2, 2, 2, 542, 543, 9, 38, 2, 2, 543, 146, 3, 2, 2, 2, 544, 546, 9, 39, 2, 2, 545, 544, 3, 2, 2, 2, 546, 547, 3, 2, 2, 2, 547, 545, 3, 2, 2, 2, 547, 548, 3, 2, 2, 2, 548, 549, 3, 2, 2, 2, 549, 550, 8, 74, 2, 2, 550, 148, 3, 2, 2, 2, 551, 555, 7, 37, 2, 2, 552, 554, 10, 40, 2, 2, 553, 552, 3, 2, 2, 2, 554, 557, 3, 2, 2, 2, 555, 553, 3, 2, 2, 2, 555, 556, 3, 2, 2, 2, 556, 558, 3, 2, 2, 2, 557, 555, 3, 2, 2, 2, 558, 559, 8, 75, 2, 2, 559, 150, 3, 2, 2, 2, 26, 2, 170, 174, 179, 183, 188, 190, 195, 203, 205, 211, 213, 221, 223, 227, 230, 458, 465, 470, 476, 482, 489, 547, 555, 3, 8, 2, 2] \ No newline at end of file diff --git a/prometheus/src/main/java/filodb/prometheus/antlr/PromQLLexer.java b/prometheus/src/main/java/filodb/prometheus/antlr/PromQLLexer.java index 8a9d194fe9..6b2fb9c597 100644 --- a/prometheus/src/main/java/filodb/prometheus/antlr/PromQLLexer.java +++ b/prometheus/src/main/java/filodb/prometheus/antlr/PromQLLexer.java @@ -1,4 +1,4 @@ -// Generated from PromQL.g4 by ANTLR 4.9.1 +// Generated from filodb/prometheus/antlr/PromQL.g4 by ANTLR 4.9.1 package filodb.prometheus.antlr; import org.antlr.v4.runtime.Lexer; import org.antlr.v4.runtime.CharStream; @@ -122,7 +122,7 @@ public PromQLLexer(CharStream input) { public ATN getATN() { return _ATN; } public static final String _serializedATN = - "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\62\u022b\b\1\4\2"+ + "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\62\u0230\b\1\4\2"+ "\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4"+ "\13\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22"+ "\t\22\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31"+ @@ -149,171 +149,173 @@ public PromQLLexer(CharStream input) { ",\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3"+ ",\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3"+ ",\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3"+ - ",\3,\3,\3,\3,\3,\5,\u01c6\n,\3-\3-\3-\6-\u01cb\n-\r-\16-\u01cc\3-\3-\3"+ - "-\5-\u01d2\n-\3.\3.\7.\u01d6\n.\f.\16.\u01d9\13.\3/\7/\u01dc\n/\f/\16"+ - "/\u01df\13/\3/\3/\7/\u01e3\n/\f/\16/\u01e6\13/\3\60\3\60\3\61\3\61\3\62"+ - "\3\62\3\63\3\63\3\64\3\64\3\65\3\65\3\66\3\66\3\67\3\67\38\38\39\39\3"+ - ":\3:\3;\3;\3<\3<\3=\3=\3>\3>\3?\3?\3@\3@\3A\3A\3B\3B\3C\3C\3D\3D\3E\3"+ - "E\3F\3F\3G\3G\3H\3H\3I\3I\3J\6J\u021d\nJ\rJ\16J\u021e\3J\3J\3K\3K\7K\u0225"+ - "\nK\fK\16K\u0228\13K\3K\3K\2\2L\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23"+ - "\13\25\f\27\r\31\16\33\17\35\20\37\21!\22#\23%\24\'\25)\26+\27-\30/\31"+ - "\61\32\63\33\65\34\67\359\36;\37= ?!A\"C#E$G%I&K\'M(O)Q*S+U,W-Y.[/]\60"+ - "_\2a\2c\2e\2g\2i\2k\2m\2o\2q\2s\2u\2w\2y\2{\2}\2\177\2\u0081\2\u0083\2"+ - "\u0085\2\u0087\2\u0089\2\u008b\2\u008d\2\u008f\2\u0091\2\u0093\61\u0095"+ - "\62\3\2)\3\2\62;\4\2GGgg\4\2--//\4\2ZZzz\5\2\62;CHch\4\2))^^\4\2$$^^\b"+ - "\2ffjjoouuyy{{\5\2C\\aac|\6\2\62;C\\aac|\4\2<\2\2\u0107\60\3\2\2\2\u0108\u0109\7@\2\2\u0109\u010a"+ - "\7?\2\2\u010a\62\3\2\2\2\u010b\u010c\7>\2\2\u010c\u010d\7?\2\2\u010d\64"+ - "\3\2\2\2\u010e\u010f\7?\2\2\u010f\u0110\7\u0080\2\2\u0110\66\3\2\2\2\u0111"+ - "\u0112\7#\2\2\u0112\u0113\7\u0080\2\2\u01138\3\2\2\2\u0114\u0115\7B\2"+ - "\2\u0115:\3\2\2\2\u0116\u0117\5_\60\2\u0117\u0118\5y=\2\u0118\u0119\5"+ - "e\63\2\u0119<\3\2\2\2\u011a\u011b\5{>\2\u011b\u011c\5\u0081A\2\u011c>"+ - "\3\2\2\2\u011d\u011e\5\u0087D\2\u011e\u011f\5y=\2\u011f\u0120\5u;\2\u0120"+ - "\u0121\5g\64\2\u0121\u0122\5\u0083B\2\u0122\u0123\5\u0083B\2\u0123@\3"+ - "\2\2\2\u0124\u0125\5a\61\2\u0125\u0126\5\u008fH\2\u0126B\3\2\2\2\u0127"+ - "\u0128\5\u008bF\2\u0128\u0129\5o8\2\u0129\u012a\5\u0085C\2\u012a\u012b"+ - "\5m\67\2\u012b\u012c\5{>\2\u012c\u012d\5\u0087D\2\u012d\u012e\5\u0085"+ - "C\2\u012eD\3\2\2\2\u012f\u0130\5{>\2\u0130\u0131\5y=\2\u0131F\3\2\2\2"+ - "\u0132\u0133\5o8\2\u0133\u0134\5k\66\2\u0134\u0135\5y=\2\u0135\u0136\5"+ - "{>\2\u0136\u0137\5\u0081A\2\u0137\u0138\5o8\2\u0138\u0139\5y=\2\u0139"+ - "\u013a\5k\66\2\u013aH\3\2\2\2\u013b\u013c\5k\66\2\u013c\u013d\5\u0081"+ - "A\2\u013d\u013e\5{>\2\u013e\u013f\5\u0087D\2\u013f\u0140\5}?\2\u0140\u0141"+ - "\7a\2\2\u0141\u0142\5u;\2\u0142\u0143\5g\64\2\u0143\u0144\5i\65\2\u0144"+ - "\u0145\5\u0085C\2\u0145J\3\2\2\2\u0146\u0147\5k\66\2\u0147\u0148\5\u0081"+ - "A\2\u0148\u0149\5{>\2\u0149\u014a\5\u0087D\2\u014a\u014b\5}?\2\u014b\u014c"+ - "\7a\2\2\u014c\u014d\5\u0081A\2\u014d\u014e\5o8\2\u014e\u014f\5k\66\2\u014f"+ - "\u0150\5m\67\2\u0150\u0151\5\u0085C\2\u0151L\3\2\2\2\u0152\u0153\5{>\2"+ - "\u0153\u0154\5i\65\2\u0154\u0155\5i\65\2\u0155\u0156\5\u0083B\2\u0156"+ - "\u0157\5g\64\2\u0157\u0158\5\u0085C\2\u0158N\3\2\2\2\u0159\u015a\5u;\2"+ - "\u015a\u015b\5o8\2\u015b\u015c\5w<\2\u015c\u015d\5o8\2\u015d\u015e\5\u0085"+ - "C\2\u015eP\3\2\2\2\u015f\u0160\5a\61\2\u0160\u0161\5{>\2\u0161\u0162\5"+ - "{>\2\u0162\u0163\5u;\2\u0163R\3\2\2\2\u0164\u0165\5\u0083B\2\u0165\u0166"+ - "\5\u0085C\2\u0166\u0167\5_\60\2\u0167\u0168\5\u0081A\2\u0168\u0169\5\u0085"+ - "C\2\u0169\u016a\7*\2\2\u016a\u016b\7+\2\2\u016bT\3\2\2\2\u016c\u016d\5"+ - "g\64\2\u016d\u016e\5y=\2\u016e\u016f\5e\63\2\u016f\u0170\7*\2\2\u0170"+ - "\u0171\7+\2\2\u0171V\3\2\2\2\u0172\u0173\5\u0083B\2\u0173\u0174\5\u0087"+ - "D\2\u0174\u0175\5w<\2\u0175\u01c6\3\2\2\2\u0176\u0177\5w<\2\u0177\u0178"+ - "\5o8\2\u0178\u0179\5y=\2\u0179\u01c6\3\2\2\2\u017a\u017b\5w<\2\u017b\u017c"+ - "\5_\60\2\u017c\u017d\5\u008dG\2\u017d\u01c6\3\2\2\2\u017e\u017f\5_\60"+ - "\2\u017f\u0180\5\u0089E\2\u0180\u0181\5k\66\2\u0181\u01c6\3\2\2\2\u0182"+ - "\u0183\5k\66\2\u0183\u0184\5\u0081A\2\u0184\u0185\5{>\2\u0185\u0186\5"+ - "\u0087D\2\u0186\u0187\5}?\2\u0187\u01c6\3\2\2\2\u0188\u0189\5\u0083B\2"+ - "\u0189\u018a\5\u0085C\2\u018a\u018b\5e\63\2\u018b\u018c\5e\63\2\u018c"+ - "\u018d\5g\64\2\u018d\u018e\5\u0089E\2\u018e\u01c6\3\2\2\2\u018f\u0190"+ - "\5\u0083B\2\u0190\u0191\5\u0085C\2\u0191\u0192\5e\63\2\u0192\u0193\5\u0089"+ - "E\2\u0193\u0194\5_\60\2\u0194\u0195\5\u0081A\2\u0195\u01c6\3\2\2\2\u0196"+ - "\u0197\5c\62\2\u0197\u0198\5{>\2\u0198\u0199\5\u0087D\2\u0199\u019a\5"+ - "y=\2\u019a\u019b\5\u0085C\2\u019b\u01c6\3\2\2\2\u019c\u019d\5c\62\2\u019d"+ - "\u019e\5{>\2\u019e\u019f\5\u0087D\2\u019f\u01a0\5y=\2\u01a0\u01a1\5\u0085"+ - "C\2\u01a1\u01a2\7a\2\2\u01a2\u01a3\5\u0089E\2\u01a3\u01a4\5_\60\2\u01a4"+ - "\u01a5\5u;\2\u01a5\u01a6\5\u0087D\2\u01a6\u01a7\5g\64\2\u01a7\u01a8\5"+ - "\u0083B\2\u01a8\u01c6\3\2\2\2\u01a9\u01aa\5a\61\2\u01aa\u01ab\5{>\2\u01ab"+ - "\u01ac\5\u0085C\2\u01ac\u01ad\5\u0085C\2\u01ad\u01ae\5{>\2\u01ae\u01af"+ - "\5w<\2\u01af\u01b0\5s:\2\u01b0\u01c6\3\2\2\2\u01b1\u01b2\5\u0085C\2\u01b2"+ - "\u01b3\5{>\2\u01b3\u01b4\5}?\2\u01b4\u01b5\5s:\2\u01b5\u01c6\3\2\2\2\u01b6"+ - "\u01b7\5\177@\2\u01b7\u01b8\5\u0087D\2\u01b8\u01b9\5_\60\2\u01b9\u01ba"+ - "\5y=\2\u01ba\u01bb\5\u0085C\2\u01bb\u01bc\5o8\2\u01bc\u01bd\5u;\2\u01bd"+ - "\u01be\5g\64\2\u01be\u01c6\3\2\2\2\u01bf\u01c0\5k\66\2\u01c0\u01c1\5\u0081"+ - "A\2\u01c1\u01c2\5{>\2\u01c2\u01c3\5\u0087D\2\u01c3\u01c4\5}?\2\u01c4\u01c6"+ - "\3\2\2\2\u01c5\u0172\3\2\2\2\u01c5\u0176\3\2\2\2\u01c5\u017a\3\2\2\2\u01c5"+ - "\u017e\3\2\2\2\u01c5\u0182\3\2\2\2\u01c5\u0188\3\2\2\2\u01c5\u018f\3\2"+ - "\2\2\u01c5\u0196\3\2\2\2\u01c5\u019c\3\2\2\2\u01c5\u01a9\3\2\2\2\u01c5"+ - "\u01b1\3\2\2\2\u01c5\u01b6\3\2\2\2\u01c5\u01bf\3\2\2\2\u01c6X\3\2\2\2"+ - "\u01c7\u01c8\5\23\n\2\u01c8\u01c9\t\t\2\2\u01c9\u01cb\3\2\2\2\u01ca\u01c7"+ - "\3\2\2\2\u01cb\u01cc\3\2\2\2\u01cc\u01ca\3\2\2\2\u01cc\u01cd\3\2\2\2\u01cd"+ - "\u01d2\3\2\2\2\u01ce\u01cf\5\23\n\2\u01cf\u01d0\7k\2\2\u01d0\u01d2\3\2"+ - "\2\2\u01d1\u01ca\3\2\2\2\u01d1\u01ce\3\2\2\2\u01d2Z\3\2\2\2\u01d3\u01d7"+ - "\t\n\2\2\u01d4\u01d6\t\13\2\2\u01d5\u01d4\3\2\2\2\u01d6\u01d9\3\2\2\2"+ - "\u01d7\u01d5\3\2\2\2\u01d7\u01d8\3\2\2\2\u01d8\\\3\2\2\2\u01d9\u01d7\3"+ - "\2\2\2\u01da\u01dc\t\f\2\2\u01db\u01da\3\2\2\2\u01dc\u01df\3\2\2\2\u01dd"+ - "\u01db\3\2\2\2\u01dd\u01de\3\2\2\2\u01de\u01e0\3\2\2\2\u01df\u01dd\3\2"+ - "\2\2\u01e0\u01e4\t\r\2\2\u01e1\u01e3\t\16\2\2\u01e2\u01e1\3\2\2\2\u01e3"+ - "\u01e6\3\2\2\2\u01e4\u01e2\3\2\2\2\u01e4\u01e5\3\2\2\2\u01e5^\3\2\2\2"+ - "\u01e6\u01e4\3\2\2\2\u01e7\u01e8\t\17\2\2\u01e8`\3\2\2\2\u01e9\u01ea\t"+ - "\20\2\2\u01eab\3\2\2\2\u01eb\u01ec\t\21\2\2\u01ecd\3\2\2\2\u01ed\u01ee"+ - "\t\22\2\2\u01eef\3\2\2\2\u01ef\u01f0\t\3\2\2\u01f0h\3\2\2\2\u01f1\u01f2"+ - "\t\23\2\2\u01f2j\3\2\2\2\u01f3\u01f4\t\24\2\2\u01f4l\3\2\2\2\u01f5\u01f6"+ - "\t\25\2\2\u01f6n\3\2\2\2\u01f7\u01f8\t\26\2\2\u01f8p\3\2\2\2\u01f9\u01fa"+ - "\t\27\2\2\u01far\3\2\2\2\u01fb\u01fc\t\30\2\2\u01fct\3\2\2\2\u01fd\u01fe"+ - "\t\31\2\2\u01fev\3\2\2\2\u01ff\u0200\t\32\2\2\u0200x\3\2\2\2\u0201\u0202"+ - "\t\33\2\2\u0202z\3\2\2\2\u0203\u0204\t\34\2\2\u0204|\3\2\2\2\u0205\u0206"+ - "\t\35\2\2\u0206~\3\2\2\2\u0207\u0208\t\36\2\2\u0208\u0080\3\2\2\2\u0209"+ - "\u020a\t\37\2\2\u020a\u0082\3\2\2\2\u020b\u020c\t \2\2\u020c\u0084\3\2"+ - "\2\2\u020d\u020e\t!\2\2\u020e\u0086\3\2\2\2\u020f\u0210\t\"\2\2\u0210"+ - "\u0088\3\2\2\2\u0211\u0212\t#\2\2\u0212\u008a\3\2\2\2\u0213\u0214\t$\2"+ - "\2\u0214\u008c\3\2\2\2\u0215\u0216\t\5\2\2\u0216\u008e\3\2\2\2\u0217\u0218"+ - "\t%\2\2\u0218\u0090\3\2\2\2\u0219\u021a\t&\2\2\u021a\u0092\3\2\2\2\u021b"+ - "\u021d\t\'\2\2\u021c\u021b\3\2\2\2\u021d\u021e\3\2\2\2\u021e\u021c\3\2"+ - "\2\2\u021e\u021f\3\2\2\2\u021f\u0220\3\2\2\2\u0220\u0221\bJ\2\2\u0221"+ - "\u0094\3\2\2\2\u0222\u0226\7%\2\2\u0223\u0225\n(\2\2\u0224\u0223\3\2\2"+ - "\2\u0225\u0228\3\2\2\2\u0226\u0224\3\2\2\2\u0226\u0227\3\2\2\2\u0227\u0229"+ - "\3\2\2\2\u0228\u0226\3\2\2\2\u0229\u022a\bK\2\2\u022a\u0096\3\2\2\2\32"+ - "\2\u00aa\u00ae\u00b3\u00b7\u00bc\u00be\u00c3\u00cb\u00cd\u00d3\u00d5\u00dd"+ - "\u00df\u00e3\u00e6\u01c5\u01cc\u01d1\u01d7\u01dd\u01e4\u021e\u0226\3\b"+ - "\2\2"; + ",\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\5,\u01cb\n,\3-\3-\3-\6-\u01d0\n-\r-\16"+ + "-\u01d1\3-\3-\3-\5-\u01d7\n-\3.\3.\7.\u01db\n.\f.\16.\u01de\13.\3/\7/"+ + "\u01e1\n/\f/\16/\u01e4\13/\3/\3/\7/\u01e8\n/\f/\16/\u01eb\13/\3\60\3\60"+ + "\3\61\3\61\3\62\3\62\3\63\3\63\3\64\3\64\3\65\3\65\3\66\3\66\3\67\3\67"+ + "\38\38\39\39\3:\3:\3;\3;\3<\3<\3=\3=\3>\3>\3?\3?\3@\3@\3A\3A\3B\3B\3C"+ + "\3C\3D\3D\3E\3E\3F\3F\3G\3G\3H\3H\3I\3I\3J\6J\u0222\nJ\rJ\16J\u0223\3"+ + "J\3J\3K\3K\7K\u022a\nK\fK\16K\u022d\13K\3K\3K\2\2L\3\3\5\4\7\5\t\6\13"+ + "\7\r\b\17\t\21\n\23\13\25\f\27\r\31\16\33\17\35\20\37\21!\22#\23%\24\'"+ + "\25)\26+\27-\30/\31\61\32\63\33\65\34\67\359\36;\37= ?!A\"C#E$G%I&K\'"+ + "M(O)Q*S+U,W-Y.[/]\60_\2a\2c\2e\2g\2i\2k\2m\2o\2q\2s\2u\2w\2y\2{\2}\2\177"+ + "\2\u0081\2\u0083\2\u0085\2\u0087\2\u0089\2\u008b\2\u008d\2\u008f\2\u0091"+ + "\2\u0093\61\u0095\62\3\2)\3\2\62;\4\2GGgg\4\2--//\4\2ZZzz\5\2\62;CHch"+ + "\4\2))^^\4\2$$^^\b\2ffjjoouuyy{{\5\2C\\aac|\6\2\62;C\\aac|\4\2<\2\2\u0107\60\3\2\2\2\u0108\u0109"+ + "\7@\2\2\u0109\u010a\7?\2\2\u010a\62\3\2\2\2\u010b\u010c\7>\2\2\u010c\u010d"+ + "\7?\2\2\u010d\64\3\2\2\2\u010e\u010f\7?\2\2\u010f\u0110\7\u0080\2\2\u0110"+ + "\66\3\2\2\2\u0111\u0112\7#\2\2\u0112\u0113\7\u0080\2\2\u01138\3\2\2\2"+ + "\u0114\u0115\7B\2\2\u0115:\3\2\2\2\u0116\u0117\5_\60\2\u0117\u0118\5y"+ + "=\2\u0118\u0119\5e\63\2\u0119<\3\2\2\2\u011a\u011b\5{>\2\u011b\u011c\5"+ + "\u0081A\2\u011c>\3\2\2\2\u011d\u011e\5\u0087D\2\u011e\u011f\5y=\2\u011f"+ + "\u0120\5u;\2\u0120\u0121\5g\64\2\u0121\u0122\5\u0083B\2\u0122\u0123\5"+ + "\u0083B\2\u0123@\3\2\2\2\u0124\u0125\5a\61\2\u0125\u0126\5\u008fH\2\u0126"+ + "B\3\2\2\2\u0127\u0128\5\u008bF\2\u0128\u0129\5o8\2\u0129\u012a\5\u0085"+ + "C\2\u012a\u012b\5m\67\2\u012b\u012c\5{>\2\u012c\u012d\5\u0087D\2\u012d"+ + "\u012e\5\u0085C\2\u012eD\3\2\2\2\u012f\u0130\5{>\2\u0130\u0131\5y=\2\u0131"+ + "F\3\2\2\2\u0132\u0133\5o8\2\u0133\u0134\5k\66\2\u0134\u0135\5y=\2\u0135"+ + "\u0136\5{>\2\u0136\u0137\5\u0081A\2\u0137\u0138\5o8\2\u0138\u0139\5y="+ + "\2\u0139\u013a\5k\66\2\u013aH\3\2\2\2\u013b\u013c\5k\66\2\u013c\u013d"+ + "\5\u0081A\2\u013d\u013e\5{>\2\u013e\u013f\5\u0087D\2\u013f\u0140\5}?\2"+ + "\u0140\u0141\7a\2\2\u0141\u0142\5u;\2\u0142\u0143\5g\64\2\u0143\u0144"+ + "\5i\65\2\u0144\u0145\5\u0085C\2\u0145J\3\2\2\2\u0146\u0147\5k\66\2\u0147"+ + "\u0148\5\u0081A\2\u0148\u0149\5{>\2\u0149\u014a\5\u0087D\2\u014a\u014b"+ + "\5}?\2\u014b\u014c\7a\2\2\u014c\u014d\5\u0081A\2\u014d\u014e\5o8\2\u014e"+ + "\u014f\5k\66\2\u014f\u0150\5m\67\2\u0150\u0151\5\u0085C\2\u0151L\3\2\2"+ + "\2\u0152\u0153\5{>\2\u0153\u0154\5i\65\2\u0154\u0155\5i\65\2\u0155\u0156"+ + "\5\u0083B\2\u0156\u0157\5g\64\2\u0157\u0158\5\u0085C\2\u0158N\3\2\2\2"+ + "\u0159\u015a\5u;\2\u015a\u015b\5o8\2\u015b\u015c\5w<\2\u015c\u015d\5o"+ + "8\2\u015d\u015e\5\u0085C\2\u015eP\3\2\2\2\u015f\u0160\5a\61\2\u0160\u0161"+ + "\5{>\2\u0161\u0162\5{>\2\u0162\u0163\5u;\2\u0163R\3\2\2\2\u0164\u0165"+ + "\5\u0083B\2\u0165\u0166\5\u0085C\2\u0166\u0167\5_\60\2\u0167\u0168\5\u0081"+ + "A\2\u0168\u0169\5\u0085C\2\u0169\u016a\7*\2\2\u016a\u016b\7+\2\2\u016b"+ + "T\3\2\2\2\u016c\u016d\5g\64\2\u016d\u016e\5y=\2\u016e\u016f\5e\63\2\u016f"+ + "\u0170\7*\2\2\u0170\u0171\7+\2\2\u0171V\3\2\2\2\u0172\u0173\5\u0083B\2"+ + "\u0173\u0174\5\u0087D\2\u0174\u0175\5w<\2\u0175\u01cb\3\2\2\2\u0176\u0177"+ + "\5w<\2\u0177\u0178\5o8\2\u0178\u0179\5y=\2\u0179\u01cb\3\2\2\2\u017a\u017b"+ + "\5w<\2\u017b\u017c\5_\60\2\u017c\u017d\5\u008dG\2\u017d\u01cb\3\2\2\2"+ + "\u017e\u017f\5_\60\2\u017f\u0180\5\u0089E\2\u0180\u0181\5k\66\2\u0181"+ + "\u01cb\3\2\2\2\u0182\u0183\5m\67\2\u0183\u0184\5_\60\2\u0184\u0185\5\u0089"+ + "E\2\u0185\u0186\5k\66\2\u0186\u01cb\3\2\2\2\u0187\u0188\5k\66\2\u0188"+ + "\u0189\5\u0081A\2\u0189\u018a\5{>\2\u018a\u018b\5\u0087D\2\u018b\u018c"+ + "\5}?\2\u018c\u01cb\3\2\2\2\u018d\u018e\5\u0083B\2\u018e\u018f\5\u0085"+ + "C\2\u018f\u0190\5e\63\2\u0190\u0191\5e\63\2\u0191\u0192\5g\64\2\u0192"+ + "\u0193\5\u0089E\2\u0193\u01cb\3\2\2\2\u0194\u0195\5\u0083B\2\u0195\u0196"+ + "\5\u0085C\2\u0196\u0197\5e\63\2\u0197\u0198\5\u0089E\2\u0198\u0199\5_"+ + "\60\2\u0199\u019a\5\u0081A\2\u019a\u01cb\3\2\2\2\u019b\u019c\5c\62\2\u019c"+ + "\u019d\5{>\2\u019d\u019e\5\u0087D\2\u019e\u019f\5y=\2\u019f\u01a0\5\u0085"+ + "C\2\u01a0\u01cb\3\2\2\2\u01a1\u01a2\5c\62\2\u01a2\u01a3\5{>\2\u01a3\u01a4"+ + "\5\u0087D\2\u01a4\u01a5\5y=\2\u01a5\u01a6\5\u0085C\2\u01a6\u01a7\7a\2"+ + "\2\u01a7\u01a8\5\u0089E\2\u01a8\u01a9\5_\60\2\u01a9\u01aa\5u;\2\u01aa"+ + "\u01ab\5\u0087D\2\u01ab\u01ac\5g\64\2\u01ac\u01ad\5\u0083B\2\u01ad\u01cb"+ + "\3\2\2\2\u01ae\u01af\5a\61\2\u01af\u01b0\5{>\2\u01b0\u01b1\5\u0085C\2"+ + "\u01b1\u01b2\5\u0085C\2\u01b2\u01b3\5{>\2\u01b3\u01b4\5w<\2\u01b4\u01b5"+ + "\5s:\2\u01b5\u01cb\3\2\2\2\u01b6\u01b7\5\u0085C\2\u01b7\u01b8\5{>\2\u01b8"+ + "\u01b9\5}?\2\u01b9\u01ba\5s:\2\u01ba\u01cb\3\2\2\2\u01bb\u01bc\5\177@"+ + "\2\u01bc\u01bd\5\u0087D\2\u01bd\u01be\5_\60\2\u01be\u01bf\5y=\2\u01bf"+ + "\u01c0\5\u0085C\2\u01c0\u01c1\5o8\2\u01c1\u01c2\5u;\2\u01c2\u01c3\5g\64"+ + "\2\u01c3\u01cb\3\2\2\2\u01c4\u01c5\5k\66\2\u01c5\u01c6\5\u0081A\2\u01c6"+ + "\u01c7\5{>\2\u01c7\u01c8\5\u0087D\2\u01c8\u01c9\5}?\2\u01c9\u01cb\3\2"+ + "\2\2\u01ca\u0172\3\2\2\2\u01ca\u0176\3\2\2\2\u01ca\u017a\3\2\2\2\u01ca"+ + "\u017e\3\2\2\2\u01ca\u0182\3\2\2\2\u01ca\u0187\3\2\2\2\u01ca\u018d\3\2"+ + "\2\2\u01ca\u0194\3\2\2\2\u01ca\u019b\3\2\2\2\u01ca\u01a1\3\2\2\2\u01ca"+ + "\u01ae\3\2\2\2\u01ca\u01b6\3\2\2\2\u01ca\u01bb\3\2\2\2\u01ca\u01c4\3\2"+ + "\2\2\u01cbX\3\2\2\2\u01cc\u01cd\5\23\n\2\u01cd\u01ce\t\t\2\2\u01ce\u01d0"+ + "\3\2\2\2\u01cf\u01cc\3\2\2\2\u01d0\u01d1\3\2\2\2\u01d1\u01cf\3\2\2\2\u01d1"+ + "\u01d2\3\2\2\2\u01d2\u01d7\3\2\2\2\u01d3\u01d4\5\23\n\2\u01d4\u01d5\7"+ + "k\2\2\u01d5\u01d7\3\2\2\2\u01d6\u01cf\3\2\2\2\u01d6\u01d3\3\2\2\2\u01d7"+ + "Z\3\2\2\2\u01d8\u01dc\t\n\2\2\u01d9\u01db\t\13\2\2\u01da\u01d9\3\2\2\2"+ + "\u01db\u01de\3\2\2\2\u01dc\u01da\3\2\2\2\u01dc\u01dd\3\2\2\2\u01dd\\\3"+ + "\2\2\2\u01de\u01dc\3\2\2\2\u01df\u01e1\t\f\2\2\u01e0\u01df\3\2\2\2\u01e1"+ + "\u01e4\3\2\2\2\u01e2\u01e0\3\2\2\2\u01e2\u01e3\3\2\2\2\u01e3\u01e5\3\2"+ + "\2\2\u01e4\u01e2\3\2\2\2\u01e5\u01e9\t\r\2\2\u01e6\u01e8\t\16\2\2\u01e7"+ + "\u01e6\3\2\2\2\u01e8\u01eb\3\2\2\2\u01e9\u01e7\3\2\2\2\u01e9\u01ea\3\2"+ + "\2\2\u01ea^\3\2\2\2\u01eb\u01e9\3\2\2\2\u01ec\u01ed\t\17\2\2\u01ed`\3"+ + "\2\2\2\u01ee\u01ef\t\20\2\2\u01efb\3\2\2\2\u01f0\u01f1\t\21\2\2\u01f1"+ + "d\3\2\2\2\u01f2\u01f3\t\22\2\2\u01f3f\3\2\2\2\u01f4\u01f5\t\3\2\2\u01f5"+ + "h\3\2\2\2\u01f6\u01f7\t\23\2\2\u01f7j\3\2\2\2\u01f8\u01f9\t\24\2\2\u01f9"+ + "l\3\2\2\2\u01fa\u01fb\t\25\2\2\u01fbn\3\2\2\2\u01fc\u01fd\t\26\2\2\u01fd"+ + "p\3\2\2\2\u01fe\u01ff\t\27\2\2\u01ffr\3\2\2\2\u0200\u0201\t\30\2\2\u0201"+ + "t\3\2\2\2\u0202\u0203\t\31\2\2\u0203v\3\2\2\2\u0204\u0205\t\32\2\2\u0205"+ + "x\3\2\2\2\u0206\u0207\t\33\2\2\u0207z\3\2\2\2\u0208\u0209\t\34\2\2\u0209"+ + "|\3\2\2\2\u020a\u020b\t\35\2\2\u020b~\3\2\2\2\u020c\u020d\t\36\2\2\u020d"+ + "\u0080\3\2\2\2\u020e\u020f\t\37\2\2\u020f\u0082\3\2\2\2\u0210\u0211\t"+ + " \2\2\u0211\u0084\3\2\2\2\u0212\u0213\t!\2\2\u0213\u0086\3\2\2\2\u0214"+ + "\u0215\t\"\2\2\u0215\u0088\3\2\2\2\u0216\u0217\t#\2\2\u0217\u008a\3\2"+ + "\2\2\u0218\u0219\t$\2\2\u0219\u008c\3\2\2\2\u021a\u021b\t\5\2\2\u021b"+ + "\u008e\3\2\2\2\u021c\u021d\t%\2\2\u021d\u0090\3\2\2\2\u021e\u021f\t&\2"+ + "\2\u021f\u0092\3\2\2\2\u0220\u0222\t\'\2\2\u0221\u0220\3\2\2\2\u0222\u0223"+ + "\3\2\2\2\u0223\u0221\3\2\2\2\u0223\u0224\3\2\2\2\u0224\u0225\3\2\2\2\u0225"+ + "\u0226\bJ\2\2\u0226\u0094\3\2\2\2\u0227\u022b\7%\2\2\u0228\u022a\n(\2"+ + "\2\u0229\u0228\3\2\2\2\u022a\u022d\3\2\2\2\u022b\u0229\3\2\2\2\u022b\u022c"+ + "\3\2\2\2\u022c\u022e\3\2\2\2\u022d\u022b\3\2\2\2\u022e\u022f\bK\2\2\u022f"+ + "\u0096\3\2\2\2\32\2\u00aa\u00ae\u00b3\u00b7\u00bc\u00be\u00c3\u00cb\u00cd"+ + "\u00d3\u00d5\u00dd\u00df\u00e3\u00e6\u01ca\u01d1\u01d6\u01dc\u01e2\u01e9"+ + "\u0223\u022b\3\b\2\2"; public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); static { diff --git a/prometheus/src/main/java/filodb/prometheus/antlr/PromQLParser.java b/prometheus/src/main/java/filodb/prometheus/antlr/PromQLParser.java index 6c11b8c79f..cd6d367221 100644 --- a/prometheus/src/main/java/filodb/prometheus/antlr/PromQLParser.java +++ b/prometheus/src/main/java/filodb/prometheus/antlr/PromQLParser.java @@ -1,4 +1,4 @@ -// Generated from PromQL.g4 by ANTLR 4.9.1 +// Generated from filodb/prometheus/antlr/PromQL.g4 by ANTLR 4.9.1 package filodb.prometheus.antlr; import org.antlr.v4.runtime.atn.*; import org.antlr.v4.runtime.dfa.DFA; diff --git a/prometheus/src/main/java/filodb/prometheus/antlr/PromQLVisitor.java b/prometheus/src/main/java/filodb/prometheus/antlr/PromQLVisitor.java index b4ad46a2f8..9f5c3e75fa 100644 --- a/prometheus/src/main/java/filodb/prometheus/antlr/PromQLVisitor.java +++ b/prometheus/src/main/java/filodb/prometheus/antlr/PromQLVisitor.java @@ -1,4 +1,4 @@ -// Generated from PromQL.g4 by ANTLR 4.9.1 +// Generated from filodb/prometheus/antlr/PromQL.g4 by ANTLR 4.9.1 package filodb.prometheus.antlr; import org.antlr.v4.runtime.tree.ParseTreeVisitor; diff --git a/prometheus/src/main/scala/filodb/prometheus/parse/LegacyParser.scala b/prometheus/src/main/scala/filodb/prometheus/parse/LegacyParser.scala index 684e6d9ee6..a9acfb73f4 100644 --- a/prometheus/src/main/scala/filodb/prometheus/parse/LegacyParser.scala +++ b/prometheus/src/main/scala/filodb/prometheus/parse/LegacyParser.scala @@ -297,6 +297,7 @@ trait AggregatesParser extends OperatorParser with BaseParser { protected val SUM = Keyword("SUM") protected val AVG = Keyword("AVG") + protected val H_AVG = Keyword("HAVG") protected val MIN = Keyword("MIN") protected val MAX = Keyword("MAX") protected val STD_DEV = Keyword("STDDEV") @@ -324,7 +325,7 @@ trait AggregatesParser extends OperatorParser with BaseParser { } lazy val aggregateOperator: PackratParser[String] = - SUM | AVG | MIN | MAX | STD_DEV | STD_VAR | COUNT_VALUES | COUNT | + SUM | AVG | H_AVG | MIN | MAX | STD_DEV | STD_VAR | COUNT_VALUES | COUNT | GROUP | BOTTOMK | TOPK | QUANTILE lazy val aggregateRangeOperator: PackratParser[String] = diff --git a/prometheus/src/test/scala/filodb/prometheus/parse/ParserSpec.scala b/prometheus/src/test/scala/filodb/prometheus/parse/ParserSpec.scala index 14f2bef850..a3de47b92b 100644 --- a/prometheus/src/test/scala/filodb/prometheus/parse/ParserSpec.scala +++ b/prometheus/src/test/scala/filodb/prometheus/parse/ParserSpec.scala @@ -675,6 +675,8 @@ class ParserSpec extends AnyFunSpec with Matchers { "Aggregate(TopK,PeriodicSeries(RawSeries(IntervalSelector(1524855988000,1524855988000),List(ColumnFilter(__name__,Equals(http_requests_total::foo))),List(bar),Some(300000),None,false),1524855988000,1000000,1524855988000,None,None),List(5.0),None)", "stdvar(http_requests_total)" -> "Aggregate(Stdvar,PeriodicSeries(RawSeries(IntervalSelector(1524855988000,1524855988000),List(ColumnFilter(__name__,Equals(http_requests_total))),List(),Some(300000),None,false),1524855988000,1000000,1524855988000,None,None),List(),None)", + "havg(rate(http_requests_total[5m]))" -> + "Aggregate(HAvg,PeriodicSeriesWithWindowing(RawSeries(IntervalSelector(1524855988000,1524855988000),List(ColumnFilter(__name__,Equals(http_requests_total))),List(),Some(300000),None,false),1524855988000,1000000,1524855988000,300000,Rate,false,List(),None,None),List(),None)", "stddev(http_requests_total)" -> "Aggregate(Stddev,PeriodicSeries(RawSeries(IntervalSelector(1524855988000,1524855988000),List(ColumnFilter(__name__,Equals(http_requests_total))),List(),Some(300000),None,false),1524855988000,1000000,1524855988000,None,None),List(),None)", "group(http_requests_total)" -> diff --git a/query/src/main/scala/filodb/query/PlanEnums.scala b/query/src/main/scala/filodb/query/PlanEnums.scala index 19f6a21119..e40ec1f373 100644 --- a/query/src/main/scala/filodb/query/PlanEnums.scala +++ b/query/src/main/scala/filodb/query/PlanEnums.scala @@ -99,6 +99,7 @@ object AggregationOperator extends Enum[AggregationOperator] { val values = findValues case object Avg extends AggregationOperator("avg") + case object HAvg extends AggregationOperator("havg") case object Count extends AggregationOperator("count") case object Group extends AggregationOperator("group") case object Sum extends AggregationOperator("sum") diff --git a/query/src/main/scala/filodb/query/exec/PeriodicSamplesMapper.scala b/query/src/main/scala/filodb/query/exec/PeriodicSamplesMapper.scala index e394ec102e..7abf00c06e 100644 --- a/query/src/main/scala/filodb/query/exec/PeriodicSamplesMapper.scala +++ b/query/src/main/scala/filodb/query/exec/PeriodicSamplesMapper.scala @@ -70,6 +70,8 @@ final case class PeriodicSamplesMapper(startMs: Long, // If a max and min column is present, the ExecPlan's job is to put it into column 3 val hasMaxMinCol = valColType == ColumnType.HistogramColumn && sourceSchema.colIDs.length > 3 && sourceSchema.columns(2).name == "max" && sourceSchema.columns(3).name == "min" + val hasHistSumCountCols = valColType == ColumnType.DoubleColumn && sourceSchema.colIDs.length == 3 && + sourceSchema.columns(1).name == "sum" && sourceSchema.columns(2).name == "count" val rangeFuncGen = RangeFunction.generatorFor(sourceSchema, functionId, valColType, querySession.queryConfig, funcParams, rawSource) @@ -101,6 +103,7 @@ final case class PeriodicSamplesMapper(startMs: Long, source.map { rv => qLogger.trace(s"Creating ChunkedWindowIterator for rv=${rv.key}, adjustedStep=$adjustedStep " + s"windowLength=$windowLength") + val mutableRow = if (hasHistSumCountCols) new HistAvgAggTransientRow() else new TransientRow() val rdrv = rv.asInstanceOf[RawDataRangeVector] val minResolutionMs = rdrv.minResolutionMs val chunkedDRangeFunc = rangeFuncGen().asChunkedD @@ -113,7 +116,7 @@ final case class PeriodicSamplesMapper(startMs: Long, s"lesser than 2 samples. Increase lookback to more than ${minResolutionMs * 2}ms") IteratorBackedRangeVector(rv.key, new ChunkedWindowIteratorD(rdrv, startWithOffset, adjustedStep, endWithOffset, - extendedWindow, chunkedDRangeFunc, querySession), outputRvRange) + extendedWindow, chunkedDRangeFunc, querySession, mutableRow), outputRvRange) } // Iterator-based: Wrap long columns to yield a double value case _: RangeFunction[_] if valColType == ColumnType.LongColumn => diff --git a/query/src/main/scala/filodb/query/exec/SelectRawPartitionsExec.scala b/query/src/main/scala/filodb/query/exec/SelectRawPartitionsExec.scala index 20c45dd109..98499c2536 100644 --- a/query/src/main/scala/filodb/query/exec/SelectRawPartitionsExec.scala +++ b/query/src/main/scala/filodb/query/exec/SelectRawPartitionsExec.scala @@ -9,6 +9,7 @@ import filodb.core.memstore.PartLookupResult import filodb.core.metadata.{Column, Schema, Schemas} import filodb.core.query.{QueryContext, QuerySession, ResultSchema} import filodb.core.store._ +import filodb.query.AggregationOperator.HAvg import filodb.query.Query import filodb.query.Query.qLogger import filodb.query.exec.rangefn.RangeFunction @@ -50,6 +51,18 @@ object SelectRawPartitionsExec extends { else false } + /** + * Checks if an AggregateMapReduce Transformer is attached + * to the MSPE and has the aggrOp argument equal to hAvg. + * This method is typically used to select sum and count columns for SelectRawPartitionsExec + * @param transformers RVTs attached to the ExecPlan node. + */ + def checkHAvgAggExists(transformers: Seq[RangeVectorTransformer]): Boolean = + transformers.exists { + case avghAmr: AggregateMapReduce => avghAmr.aggrOp == HAvg + case _ => false + } + def findFirstRangeFunction(transformers: Seq[RangeVectorTransformer]): Option[InternalRangeFunction] = transformers.collectFirst { case p: PeriodicSamplesMapper => p.functionId }.flatten @@ -97,6 +110,13 @@ object SelectRawPartitionsExec extends { val colIds = dataSchema.colIDs(colNames: _*) require(colIds.isGood, s"$colNames is not a valid column name.") colIds.get + } else if (checkHAvgAggExists(transformers)) { + // select sum & count columns + val hAvgCols = Seq("sum", "count") + val colIds = dataSchema.colIDs(hAvgCols: _*) + require(colIds.isGood, + s"Histogram average can be applied only on types that have both sum & count columns, such as a histogram") + colIds.get } else if (dataSchema != Schemas.dsGauge) { // needs to select raw data dataSchema.colIDs(dataSchema.data.valueColName).get diff --git a/query/src/main/scala/filodb/query/exec/aggregator/HistAvgRowAggregator.scala b/query/src/main/scala/filodb/query/exec/aggregator/HistAvgRowAggregator.scala new file mode 100644 index 0000000000..bb30dc1da2 --- /dev/null +++ b/query/src/main/scala/filodb/query/exec/aggregator/HistAvgRowAggregator.scala @@ -0,0 +1,68 @@ +package filodb.query.exec.aggregator + +import filodb.core.query._ +import filodb.memory.format.RowReader + +/** + * RowAggregator for Histogram Average in one step, rather than the traditional method of + * calculating the sum of sums and dividing it by the sum of counts. + * + * Map: Every histogram sample is mapped to two values, excluding the timestamp: + * (a) The mean of all observations of the histogram row (b) and the row's count column. + * + * ReduceAggregate: Accumulator maintains the (a) current mean and (b) sum of counts. + * Reduction happens by recalculating mean as (mean1*count1 + mean2*count1) / (count1+count2) + * and count as (count1 + count2) + * + * ReduceMappedRow: Same as ReduceAggregate + * + * Present: The current mean is presented. Count value is dropped from presentation + */ +object HistAvgRowAggregator extends RowAggregator { + class HistAvgHolder(var timestamp: Long = 0L, + var mean: Double = Double.NaN, + var count: Double = 0d) extends AggregateHolder { + val row = new HistAvgAggTransientRow() + def toRowReader: MutableRowReader = { + row.setLong(0, timestamp) + row.setDouble(1, mean) + row.setDouble(2, count) + row + } + def resetToZero(): Unit = { count = 0d; mean = Double.NaN } + } + type AggHolderType = HistAvgHolder + def zero: HistAvgHolder = new HistAvgHolder() + def newRowToMapInto: MutableRowReader = new HistAvgAggTransientRow() + def map(rvk: RangeVectorKey, item: RowReader, mapInto: MutableRowReader): RowReader = { + // A histogram row is composed of 3+ columns: 1: Timestamp, 2: Sum, 3: Count + val sum = item.getDouble(1) + val count = item.getDouble(2) + + mapInto.setLong(0, item.getLong(0)) + // We calculate the mean by dividing the sum by the count. + mapInto.setDouble(1, if (count.isNaN || count == 0d) 0d else sum/count) + mapInto.setDouble(2, count) + mapInto + } + def reduceAggregate(acc: HistAvgHolder, aggRes: RowReader): HistAvgHolder = { + acc.timestamp = aggRes.getLong(0) + if (!aggRes.getDouble(1).isNaN && !aggRes.getDouble(2).isNaN) { + if (acc.mean.isNaN) acc.mean = 0d + if (acc.count.isNaN) acc.count = 0d + val newMean = (acc.mean * acc.count + aggRes.getDouble(1) * aggRes.getDouble(2)) / + (acc.count + aggRes.getDouble(2)) + acc.mean = newMean + acc.count += aggRes.getDouble(2) + } + acc + } + // ignore last count column. we rely on schema change + def present(aggRangeVector: RangeVector, limit: Int, rangeParams: RangeParams, + queryStats: QueryStats): Seq[RangeVector] = Seq(aggRangeVector) + def reductionSchema(source: ResultSchema): ResultSchema = source + def presentationSchema(reductionSchema: ResultSchema): ResultSchema = { + // drop last column with count + reductionSchema.copy(reductionSchema.columns.filterNot(_.name.equals("count"))) + } +} \ No newline at end of file diff --git a/query/src/main/scala/filodb/query/exec/aggregator/RowAggregator.scala b/query/src/main/scala/filodb/query/exec/aggregator/RowAggregator.scala index 07be3f44c7..0862e4207f 100644 --- a/query/src/main/scala/filodb/query/exec/aggregator/RowAggregator.scala +++ b/query/src/main/scala/filodb/query/exec/aggregator/RowAggregator.scala @@ -117,6 +117,15 @@ object RowAggregator { schema.columns(2).name == "max" && schema.columns(3).name == "min" + /** + * Checks whether the given result schema has count and sum columns. + * This will be the case when querying "havg" on histograms. + */ + def isHistSumCount(schema: ResultSchema): Boolean = { + schema.columns.length == 3 && (schema.columns(1).name == "sum" || schema.columns(1).name == "value") && + schema.columns(2).name == "count" + } + /** * Factory for RowAggregator */ @@ -127,6 +136,7 @@ object RowAggregator { case Max if valColType != ColumnType.HistogramColumn => MaxRowAggregator case Sum if valColType == ColumnType.DoubleColumn => SumRowAggregator case Sum if isHistMaxMin(valColType, schema) => HistMaxMinSumAggregator + case HAvg if isHistSumCount(schema) => HistAvgRowAggregator case Sum if valColType == ColumnType.HistogramColumn => HistSumRowAggregator case Count if valColType == ColumnType.DoubleColumn => CountRowAggregator.double case Count if valColType == ColumnType.HistogramColumn => CountRowAggregator.hist diff --git a/query/src/main/scala/filodb/query/exec/rangefn/AggrOverTimeFunctions.scala b/query/src/main/scala/filodb/query/exec/rangefn/AggrOverTimeFunctions.scala index 453beb8912..4d8569dd16 100644 --- a/query/src/main/scala/filodb/query/exec/rangefn/AggrOverTimeFunctions.scala +++ b/query/src/main/scala/filodb/query/exec/rangefn/AggrOverTimeFunctions.scala @@ -5,7 +5,7 @@ import java.util import debox.Buffer -import filodb.core.query.{QueryConfig, TransientHistMaxMinRow, TransientHistRow, TransientRow} +import filodb.core.query.{HistAvgAggTransientRow, QueryConfig, TransientHistMaxMinRow, TransientHistRow, TransientRow} import filodb.core.store.ChunkSetInfoReader import filodb.memory.format.{BinaryVector, CounterVectorReader, MemoryReader, VectorDataReader} import filodb.memory.format.{vectors => bv} @@ -768,6 +768,65 @@ class DeltaRateAndMinMaxOverTimeFuncHD(maxColId: Int, minColId: Int) } } +/** + * Composite range function to calculate rate/increase for two columns that are cumulative counters. + * Typically, it is activated when the "havg" function is invoked to be able to + * calculate the rate for both sum and count columns simultaneously. + * @param sumFunc The range function to be used for the sum column + * @param countFunc The range function to be used for the count column + */ +class ChunkedSumCountCumulRangeFunctionDD(sumColId: Int, countColId: Int, + sumFunc: ChunkedRateFunctionBase, + countFunc: ChunkedRateFunctionBase) + extends ChunkedRangeFunction[HistAvgAggTransientRow] { + + private val tr = new TransientRow() + + override final def reset(): Unit = { + sumFunc.reset() + countFunc.reset() + } + + override def apply(windowStart: Long, windowEnd: Long, sampleToEmit: HistAvgAggTransientRow): Unit = { + // Since the underlying ChunkedRangeFunctionBase objects support only two columns using TransientRow, + // we use a temporary TransientRow ("tr" in this case) instance to get the result and put it back into sampleToEmit. + // We can optimize this by having ChunkedRangeFunctionBase accept a column number to set. + // But this work is deferred for later + sampleToEmit.setLong(0, windowEnd) + sumFunc.apply(windowStart, windowEnd, tr) + sampleToEmit.setDouble(1, tr.getDouble(1)) + countFunc.apply(windowStart, windowEnd, tr) + sampleToEmit.setDouble(2, tr.getDouble(1)) + } + final def apply(endTimestamp: Long, sampleToEmit: HistAvgAggTransientRow): Unit = ??? // should not be invoked + + import BinaryVector.BinaryVectorPtr + + // scalastyle:off parameter.number + def addChunks(tsVectorAcc: MemoryReader, tsVector: BinaryVectorPtr, tsReader: bv.LongVectorDataReader, + valueVectorAcc: MemoryReader, valueVector: BinaryVectorPtr, valueReader: VectorDataReader, + startTime: Long, endTime: Long, info: ChunkSetInfoReader, queryConfig: QueryConfig): Unit = { + // Do BinarySearch for start/end pos only once for all columns == WIN! + val startRowNum = tsReader.binarySearch(tsVectorAcc, tsVector, startTime) & 0x7fffffff + val endRowNum = Math.min(tsReader.ceilingIndex(tsVectorAcc, tsVector, endTime), info.numRows - 1) + + // At least one sample is present + if (startRowNum <= endRowNum) { + + // Get valueVector/reader for sum column + val sumVectAcc = info.vectorAccessor(sumColId) + val sumVectPtr = info.vectorAddress(sumColId) + sumFunc.addTimeChunks(sumVectAcc, sumVectPtr, bv.DoubleVector(sumVectAcc, sumVectPtr), + startRowNum, endRowNum, startTime, endTime) + + // Get valueVector/reader for count column + val countVectAcc = info.vectorAccessor(countColId) + val countVectPtr = info.vectorAddress(countColId) + countFunc.addTimeChunks(countVectAcc, countVectPtr, bv.DoubleVector(countVectAcc, countVectPtr), + startRowNum, endRowNum, startTime, endTime) + } + } +} /** * Computes Average Over Time using sum and count columns. diff --git a/query/src/main/scala/filodb/query/exec/rangefn/RangeFunction.scala b/query/src/main/scala/filodb/query/exec/rangefn/RangeFunction.scala index 9d8378f33d..d636409848 100644 --- a/query/src/main/scala/filodb/query/exec/rangefn/RangeFunction.scala +++ b/query/src/main/scala/filodb/query/exec/rangefn/RangeFunction.scala @@ -8,8 +8,8 @@ import filodb.memory.format.{vectors => bv, _} import filodb.memory.format.BinaryVector.BinaryVectorPtr import filodb.memory.format.vectors.HistogramWithBuckets import filodb.query.Query -//import filodb.query.RangeFunctionId.MedianAbsoluteDeviationOverTime import filodb.query.exec._ +import filodb.query.exec.aggregator.RowAggregator /** * Container for samples within a window of samples @@ -334,7 +334,7 @@ object RangeFunction { /** * Returns a function to generate a ChunkedRangeFunction for Double columns */ - // scalastyle:off cyclomatic.complexity + // scalastyle:off cyclomatic.complexity method.length def doubleChunkedFunction(schema: ResultSchema, func: Option[InternalRangeFunction], config: QueryConfig, @@ -342,15 +342,34 @@ object RangeFunction { func match { case None => () => new LastSampleChunkedFunctionD case Some(Last) => () => new LastSampleChunkedFunctionD + case Some(Increase) if config.fasterRateEnabled && schema.columns(1).isCumulative && + RowAggregator.isHistSumCount(schema) + => () => new ChunkedSumCountCumulRangeFunctionDD(1, 2, + new ChunkedIncreaseFunction, + new ChunkedIncreaseFunction) case Some(Increase) if config.fasterRateEnabled && schema.columns(1).isCumulative => () => new ChunkedIncreaseFunction + case Some(Rate) if config.fasterRateEnabled && schema.columns(1).isCumulative && + RowAggregator.isHistSumCount(schema) + => () => new ChunkedSumCountCumulRangeFunctionDD(1, 2, + new ChunkedRateFunction, + new ChunkedRateFunction) case Some(Rate) if config.fasterRateEnabled && schema.columns(1).isCumulative => () => new ChunkedRateFunction + case Some(Increase) if config.fasterRateEnabled && !schema.columns(1).isCumulative && + RowAggregator.isHistSumCount(schema) + => () => new ChunkedSumCountDeltaRangeFunctionDD(1, 2, + new SumOverTimeChunkedFunctionD, + new SumOverTimeChunkedFunctionD) case Some(Increase) if !schema.columns(1).isCumulative => () => new SumOverTimeChunkedFunctionD + case Some(Rate) if config.fasterRateEnabled && !schema.columns(1).isCumulative && + RowAggregator.isHistSumCount(schema) + => () => new ChunkedSumCountDeltaRangeFunctionDD(1, 2, + new RateOverDeltaChunkedFunctionD, + new RateOverDeltaChunkedFunctionD) case Some(Rate) if !schema.columns(1).isCumulative => () => new RateOverDeltaChunkedFunctionD - case Some(CountOverTime) => () => new CountOverTimeChunkedFunctionD() case Some(SumOverTime) => () => new SumOverTimeChunkedFunctionD case Some(AvgWithSumAndCountOverTime) diff --git a/query/src/main/scala/filodb/query/exec/rangefn/RateFunctions.scala b/query/src/main/scala/filodb/query/exec/rangefn/RateFunctions.scala index 24c3062fce..de1acd2b43 100644 --- a/query/src/main/scala/filodb/query/exec/rangefn/RateFunctions.scala +++ b/query/src/main/scala/filodb/query/exec/rangefn/RateFunctions.scala @@ -2,7 +2,8 @@ package filodb.query.exec.rangefn import spire.syntax.cfor._ -import filodb.core.query.{QueryConfig, TransientHistRow, TransientRow} +import filodb.core.query.{HistAvgAggTransientRow, QueryConfig, TransientHistRow, TransientRow} +import filodb.core.store.ChunkSetInfoReader import filodb.memory.format.{ vectors => bv, BinaryVector, CounterVectorReader, MemoryReader, VectorDataReader} import filodb.memory.format.BinaryVector.BinaryVectorPtr import filodb.memory.format.vectors.{Base2ExpHistogramBuckets, MutableHistogram} @@ -442,6 +443,63 @@ class RateOverDeltaChunkedFunctionD extends ChunkedDoubleRangeFunction { override def apply(endTimestamp: Long, sampleToEmit: TransientRow): Unit = ??? } +/** + * Composite range function to calculate rate/increase for two columns that are delta counters. + * Typically, it is activated when the "havg" function is invoked to be able to + * calculate the rate for both sum and count columns simultaneously. + * @param sumFunc The range function to be used for the sum column + * @param countFunc The range function to be used for the count column + */ +class ChunkedSumCountDeltaRangeFunctionDD(sumColId: Int, countColId: Int, + sumFunc: ChunkedDoubleRangeFunction, + countFunc: ChunkedDoubleRangeFunction) + extends ChunkedRangeFunction[HistAvgAggTransientRow] { + private val tr = new TransientRow() + + override final def reset(): Unit = { + sumFunc.reset() + countFunc.reset() + } + + override def apply(windowStart: Long, windowEnd: Long, sampleToEmit: HistAvgAggTransientRow): Unit = { + // Since the underlying ChunkedDoubleRangeFunction objects support only two columns using TransientRow, + // we use a temporary TransientRow ("tr" in this case) instance to get the result and put it back into sampleToEmit. + // We can optimize this by having ChunkedDoubleRangeFunction accept a column number to set. + // But this work is deferred for later + sampleToEmit.setLong(0, windowEnd) + sumFunc.apply(windowStart, windowEnd, tr) + sampleToEmit.setDouble(1, tr.getDouble(1)) + countFunc.apply(windowStart, windowEnd, tr) + sampleToEmit.setDouble(2, tr.getDouble(1)) + } + + override def apply(endTimestamp: Long, sampleToEmit: HistAvgAggTransientRow): Unit = ??? + + // scalastyle:off parameter.number + def addChunks(tsVectorAcc: MemoryReader, tsVector: BinaryVectorPtr, tsReader: bv.LongVectorDataReader, + valueVectorAcc: MemoryReader, valueVector: BinaryVectorPtr, valueReader: VectorDataReader, + startTime: Long, endTime: Long, info: ChunkSetInfoReader, queryConfig: QueryConfig): Unit = { + // Do BinarySearch for start/end pos only once for all columns == WIN! + val startRowNum = tsReader.binarySearch(tsVectorAcc, tsVector, startTime) & 0x7fffffff + val endRowNum = Math.min(tsReader.ceilingIndex(tsVectorAcc, tsVector, endTime), info.numRows - 1) + + // At least one sample is present + if (startRowNum <= endRowNum) { + + // Get valueVector/reader for max column + val sumVectAcc = info.vectorAccessor(sumColId) + val sumVectPtr = info.vectorAddress(sumColId) + sumFunc.addTimeDoubleChunks(sumVectAcc, sumVectPtr, bv.DoubleVector(sumVectAcc, sumVectPtr), + startRowNum, endRowNum) + + // Get valueVector/reader for min column + val countVectAcc = info.vectorAccessor(countColId) + val countVectPtr = info.vectorAddress(countColId) + countFunc.addTimeDoubleChunks(countVectAcc, countVectPtr, bv.DoubleVector(countVectAcc, countVectPtr), + startRowNum, endRowNum) + } + } +} class RateOverDeltaChunkedFunctionL extends ChunkedLongRangeFunction { private val sumFunc = new SumOverTimeChunkedFunctionL diff --git a/query/src/test/scala/filodb/query/exec/AggrOverRangeVectorsSpec.scala b/query/src/test/scala/filodb/query/exec/AggrOverRangeVectorsSpec.scala index ac436dbfaf..8ce46586b1 100644 --- a/query/src/test/scala/filodb/query/exec/AggrOverRangeVectorsSpec.scala +++ b/query/src/test/scala/filodb/query/exec/AggrOverRangeVectorsSpec.scala @@ -9,6 +9,7 @@ import org.scalatest.concurrent.ScalaFutures import filodb.core.{MachineMetricsData => MMD} import filodb.core.metadata.Column.ColumnType import filodb.core.query._ +import filodb.memory.format.RowReader import filodb.memory.format.ZeroCopyUTF8String._ import filodb.query.AggregationOperator import filodb.query.exec.aggregator.RowAggregator @@ -179,6 +180,116 @@ class AggrOverRangeVectorsSpec extends RawDataWindowingSpec with ScalaFutures { compareIter(result10(0).rows().map(_.getDouble(1)), readyToAggr10.map { v => 1d }.iterator) } + it ("should optimize histogram average using the havg function ") { + + def tuple3ToRR(t3: (Long, Double, Double)) = new RowReader() { + override def notNull(columnNo: Int): Boolean = ??? + override def getBoolean(columnNo: Int): Boolean = ??? + override def getInt(columnNo: Int): Int = ??? + override def getLong(columnNo: Int): Long = { + if(columnNo == 0){ + t3._1 + } else { + throw new IllegalStateException() + } + } + override def getDouble(columnNo: Int): Double = { + if(columnNo == 1){ + t3._2 + } else if(columnNo == 2){ + t3._3 + } else { + throw new IllegalStateException() + } + } + override def getFloat(columnNo: Int): Float = ??? + override def getString(columnNo: Int): String = ??? + override def getAny(columnNo: Int): Any = ??? + override def getBlobBase(columnNo: Int): Any = ??? + override def getBlobOffset(columnNo: Int): Long = ??? + override def getBlobNumBytes(columnNo: Int): Int = ??? + } + + val dps1 = Seq( + (200L, 30d, 3d), + (220L, 40d, 4d), + (240L, 20d, 2d), + (260L, 60d, 6d), + (280L, 30d, 3d), + ).map(tuple3ToRR) + + val dps2 = Seq( + (200L, 30d, 3d), + (220L, 50d, 5d), + (240L, 20d, 2d), + (260L, 40d, 4d), + (280L, 30d, 3d), + ).map(tuple3ToRR) + + val dps3 = Seq( + (200L, 50d, 5d), + (220L, 40d, 4d), + (240L, 30d, 3d), + (260L, 40d, 4d), + (280L, 20d, 2d), + ).map(tuple3ToRR) + + val rv1 = new RangeVector { + import NoCloseCursor._ + override def key: RangeVectorKey = ignoreKey + override def rows(): RangeVectorCursor = dps1.iterator + override def outputRange: Option[RvRange] = None + } + + val rv2 = new RangeVector { + import NoCloseCursor._ + override def key: RangeVectorKey = ignoreKey + override def rows(): RangeVectorCursor = dps2.iterator + override def outputRange: Option[RvRange] = None + } + + val rv3 = new RangeVector { + import NoCloseCursor._ + override def key: RangeVectorKey = ignoreKey + override def rows(): RangeVectorCursor = dps3.iterator + override def outputRange: Option[RvRange] = None + } + + val expectedAvg = Seq( + (200L, 10d), + (220L, 10d), + (240L, 10d), + (260L, 10d), + (280L, 10d), + ) + + val rvs = Seq(rv1, rv2, rv3) + // HAvg + val tscSchema = ResultSchema(Seq( + ColumnInfo("timestamp", ColumnType.TimestampColumn), + ColumnInfo("value", ColumnType.DoubleColumn), + ColumnInfo("count", ColumnType.DoubleColumn)), + 1) + + val agg4 = RowAggregator(AggregationOperator.HAvg, Nil, tscSchema) + val resultObs4a = RangeVectorAggregator.mapReduce( + agg4, false, Observable.fromIterable(rvs), noGrouping, queryContext = qc, QueryWarnings() + ) + val resultObs4 = RangeVectorAggregator.mapReduce( + agg4, true, resultObs4a, rv=>rv.key, queryContext = qc, QueryWarnings() + ) + val result4 = resultObs4.toListL.runToFuture.futureValue + result4.size shouldEqual 1 + result4(0).key shouldEqual noKey + + val resultAvg = result4(0).rows().map(rr => (rr.getLong(0), rr.getDouble(1))).toList + + resultAvg shouldEqual expectedAvg + + agg4.reductionSchema(tscSchema) shouldEqual tscSchema + agg4.presentationSchema(tscSchema) shouldEqual tvSchema + } + private def stdvar(items: List[Double]): Double = { val mean = items.sum / items.size items.map(i => math.pow((i-mean), 2)).sum / items.size