diff --git a/coordinator/src/main/scala/filodb.coordinator/queryplanner/LogicalPlanUtils.scala b/coordinator/src/main/scala/filodb.coordinator/queryplanner/LogicalPlanUtils.scala index 5a8f690f41..0de0433530 100644 --- a/coordinator/src/main/scala/filodb.coordinator/queryplanner/LogicalPlanUtils.scala +++ b/coordinator/src/main/scala/filodb.coordinator/queryplanner/LogicalPlanUtils.scala @@ -641,4 +641,17 @@ object LogicalPlanUtils extends StrictLogging { .distinct .map(_.toSeq) } + + def getLogicalPlanTreeStringRepresentation(logicalPlan: LogicalPlan) : String = { + // iterate over all the children of the logical plan and get the string representation + val children = logicalPlan match { + case nl: NonLeafLogicalPlan => nl.children.map(getLogicalPlanTreeStringRepresentation) + case _ => Seq() + } + if (children.isEmpty) { + logicalPlan.getClass.getSimpleName + } else { + s"${logicalPlan.getClass.getSimpleName}(${children.mkString(",")})" + } + } } diff --git a/coordinator/src/test/scala/filodb.coordinator/queryplanner/LogicalPlanUtilsSpec.scala b/coordinator/src/test/scala/filodb.coordinator/queryplanner/LogicalPlanUtilsSpec.scala index 2c75054084..216a39a426 100644 --- a/coordinator/src/test/scala/filodb.coordinator/queryplanner/LogicalPlanUtilsSpec.scala +++ b/coordinator/src/test/scala/filodb.coordinator/queryplanner/LogicalPlanUtilsSpec.scala @@ -181,4 +181,14 @@ class LogicalPlanUtilsSpec extends AnyFunSpec with Matchers { getMaxLookbackInMillis(query1) shouldEqual 900000 // max of 15 and 10m getMaxLookbackInMillis(query2) shouldEqual 300000 // default lookback is 5m } + + it ("getLogicalPlanTreeStringRepresentation should return result as expected") { + val timeParamsSec = TimeStepParams(1000, 10, 10000) + val query1 = """rate(test_metric{_ns_="test-ns", _ws_="test-ns", cluster="test1"}[15m]) + rate(test_metric{_ns_="test-ns", _ws_="test-ns", cluster="test1"}[10m])""" + val query2 = """test_metric{_ns_="test-ns", _ws_="test-ns", cluster="test1"} offset 1d * 1000""" + val lp = Parser.queryRangeToLogicalPlan(query1, timeParamsSec) + LogicalPlanUtils.getLogicalPlanTreeStringRepresentation(lp) shouldEqual "BinaryJoin(PeriodicSeriesWithWindowing(RawSeries),PeriodicSeriesWithWindowing(RawSeries))" + val lp2 = Parser.queryToLogicalPlan(query2, 100, 10) + LogicalPlanUtils.getLogicalPlanTreeStringRepresentation(lp2) shouldEqual "ScalarVectorBinaryOperation(PeriodicSeries(RawSeries),ScalarFixedDoublePlan)" + } }