/* *************************************************************************************** * Copyright (C) 2006 EsperTech, Inc. All rights reserved. * * http://www.espertech.com/esper * * http://www.espertech.com * * ---------------------------------------------------------------------------------- * * The software in this package is published under the terms of the GPL license * * a copy of which has been included with this distribution in the license.txt file. * *************************************************************************************** */ package com.espertech.esper.regression.spatial; import com.espertech.esper.client.*; import com.espertech.esper.client.deploy.DeploymentResult; import com.espertech.esper.client.scopetest.EPAssertionUtil; import com.espertech.esper.client.scopetest.SupportUpdateListener; import com.espertech.esper.epl.join.util.QueryPlanIndexDescOnExpr; import com.espertech.esper.epl.join.util.QueryPlanIndexDescSubquery; import com.espertech.esper.filter.FilterOperator; import com.espertech.esper.metrics.instrumentation.InstrumentationHelper; import com.espertech.esper.spatial.quadtree.core.BoundingBox; import com.espertech.esper.supportregression.bean.SupportSpatialAABB; import com.espertech.esper.supportregression.bean.SupportSpatialDualPoint; import com.espertech.esper.supportregression.bean.SupportSpatialPoint; import com.espertech.esper.supportregression.client.SupportConfigFactory; import com.espertech.esper.supportregression.epl.SupportQueryPlanIndexHook; import com.espertech.esper.supportregression.util.*; import junit.framework.TestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.*; import static com.espertech.esper.supportregression.util.SupportSpatialUtil.*; public class TestSpatialPointRegionQuadTree extends TestCase { private static final Logger log = LoggerFactory.getLogger(TestSpatialPointRegionQuadTree.class); private final static List<BoundingBox> BOXES = Arrays.asList( new BoundingBox(0, 0, 50, 50), new BoundingBox(50, 0, 100, 50), new BoundingBox(0, 50, 50, 100), new BoundingBox(50, 50, 100, 100), new BoundingBox(25, 25, 75, 75) ); private EPServiceProvider epService; private SupportUpdateListener listener; public void setUp() { Configuration config = SupportConfigFactory.getConfiguration(); config.getEngineDefaults().getExecution().setAllowIsolatedService(true); config.getEngineDefaults().getLogging().setEnableQueryPlan(true); epService = EPServiceProviderManager.getDefaultProvider(config); epService.initialize(); for (Class clazz : Arrays.asList(SupportSpatialPoint.class, SupportSpatialAABB.class, MyEventRectangleWithOffset.class, SupportSpatialDualPoint.class)) { epService.getEPAdministrator().getConfiguration().addEventType(clazz); } if (InstrumentationHelper.ENABLED) { InstrumentationHelper.startTest(epService, this.getClass(), getName()); } listener = new SupportUpdateListener(); } protected void tearDown() throws Exception { if (InstrumentationHelper.ENABLED) { InstrumentationHelper.endTest(); } listener = null; } public void testInvalid() throws Exception { runAssertionInvalidEventIndexCreate(); runAssertionInvalidEventIndexRuntime(); runAssertionInvalidMethod(); runAssertionInvalidFilterIndex(); runAssertionDocSample(); } public void testFilterIndex() throws Exception { runAssertionFilterIndexPerfStatement(); runAssertionFilterIndexPerfContextPartition(); runAssertionFilterIndexPerfPattern(); runAssertionFilterIndexUnoptimized(); runAssertionFilterIndexTypeAssertion(); } public void testEventIndex() throws Exception { runAssertionEventIndexUnindexed(); runAssertionEventIndexUnusedOnTrigger(); runAssertionEventIndexUnusedNamedWindowFireAndForget(); runAssertionEventIndexOnTriggerNWInsertRemove(false); runAssertionEventIndexOnTriggerNWInsertRemove(true); runAssertionEventIndexOnTriggerContextParameterized(); runAssertionEventIndexSubqNamedWindowIndexShare(); runAssertionEventIndexOnTriggerTable(); runAssertionEventIndexChoiceOfTwo(); runAssertionEventIndexExpression(); runAssertionEventIndexUnique(); runAssertionEventIndexPerformance(); runAssertionEventIndexChoiceBetweenIndexTypes(); runAssertionEventIndexTableFireAndForget(); runAssertionEventIndexNWFireAndForgetPerformance(); } private void runAssertionEventIndexNWFireAndForgetPerformance() throws Exception { String epl = "create window MyPointWindow#keepall as (id string, px double, py double);\n" + "insert into MyPointWindow select id, px, py from SupportSpatialPoint;\n" + "create index Idx on MyPointWindow( (px, py) pointregionquadtree(0, 0, 100, 100));\n"; String deploymentId = epService.getEPAdministrator().getDeploymentAdmin().parseDeploy(epl).getDeploymentId(); Random random = new Random(); List<SupportSpatialPoint> points = new ArrayList<>(); for (int i = 0; i < 10000; i++) { double px = random.nextDouble() * 100; double py = random.nextDouble() * 100; SupportSpatialPoint point = new SupportSpatialPoint("P" + Integer.toString(i), px, py); epService.getEPRuntime().sendEvent(point); points.add(point); // Comment-me-in: log.info("Point P" + i + " " + px + " " + py); } EPOnDemandPreparedQueryParameterized prepared = epService.getEPRuntime().prepareQueryWithParameters("select * from MyPointWindow where point(px,py).inside(rectangle(?,?,?,?))"); long start = System.currentTimeMillis(); String[] fields = "id".split(","); for (int i = 0; i < 500; i++) { double x = random.nextDouble() * 100; double y = random.nextDouble() * 100; // Comment-me-in: log.info("Query " + x + " " + y + " " + width + " " + height); prepared.setObject(1, x); prepared.setObject(2, y); prepared.setObject(3, 5); prepared.setObject(4, 5); EventBean[] events = epService.getEPRuntime().executeQuery(prepared).getArray(); Object[][] expected = SupportSpatialUtil.getExpected(points, x, y, 5, 5); EPAssertionUtil.assertPropsPerRowAnyOrder(events, fields, expected); } long delta = System.currentTimeMillis() - start; assertTrue("delta=" + delta, delta < 1000); epService.getEPAdministrator().getDeploymentAdmin().undeploy(deploymentId); } private void runAssertionFilterIndexTypeAssertion() { String eplNoIndex = "select * from SupportSpatialAABB(point(0, 0).inside(rectangle(x, y, width, height)))"; SupportFilterHelper.assertFilterMulti(epService, eplNoIndex, "SupportSpatialAABB", new SupportFilterItem[][] {{SupportFilterItem.getBoolExprFilterItem()}}); String eplIndexed = "expression myindex {pointregionquadtree(0, 0, 100, 100)}" + "select * from SupportSpatialAABB(point(0, 0, filterindex:myindex).inside(rectangle(x, y, width, height)))"; SupportFilterHelper.assertFilterMulti(epService, eplIndexed, "SupportSpatialAABB", new SupportFilterItem[][] {{new SupportFilterItem("x,y,width,height/myindex/pointregionquadtree/0.0,0.0,100.0,100.0,4.0,20.0", FilterOperator.ADVANCED_INDEX)}}); epService.getEPAdministrator().destroyAllStatements(); } private void runAssertionInvalidFilterIndex() { // unrecognized named parameter SupportMessageAssertUtil.tryInvalid(epService, "select * from SupportSpatialAABB#keepall where point(0, 0, a:1).inside(rectangle(x, y, width, height))", "Error validating expression: Failed to validate filter expression 'point(0,0,a:1).inside(rectangle(x,y...(50 chars)': point does not accept 'a' as a named parameter"); // not a filter SupportMessageAssertUtil.tryInvalid(epService, "expression myindex {pointregionquadtree(0, 0, 100, 100)} select * from SupportSpatialAABB#keepall where point(0, 0, filterindex:myindex).inside(rectangle(x, y, width, height))", "Error validating expression: Failed to validate filter expression 'point(0,0,filterindex:myindex()).in...(68 chars)': The 'filterindex' named parameter can only be used in in filter expressions"); // invalid index expression SupportMessageAssertUtil.tryInvalid(epService, "select * from SupportSpatialAABB(point(0, 0, filterindex:1).inside(rectangle(x, y, width, height)))", "Failed to validate filter expression 'point(0,0,filterindex:1).inside(rec...(60 chars)': Named parameter 'filterindex' requires an expression name"); SupportMessageAssertUtil.tryInvalid(epService, "select * from SupportSpatialAABB(point(0, 0, filterindex:dummy).inside(rectangle(x, y, width, height)))", "Failed to validate filter expression 'point(0,0,filterindex:dummy).inside...(64 chars)': Named parameter 'filterindex' requires an expression name"); SupportMessageAssertUtil.tryInvalid(epService, "expression myindex {0} select * from SupportSpatialAABB(point(0, 0, filterindex:myindex).inside(rectangle(x, y, width, height)))", "Failed to validate filter expression 'point(0,0,filterindex:myindex()).in...(68 chars)': Named parameter 'filterindex' requires an index expression"); SupportMessageAssertUtil.tryInvalid(epService, "expression myindex {dummy(0)} select * from SupportSpatialAABB(point(0, 0, filterindex:myindex).inside(rectangle(x, y, width, height)))", "Failed to validate filter expression 'point(0,0,filterindex:myindex()).in...(68 chars)': Unrecognized advanced-type index 'dummy'"); SupportMessageAssertUtil.tryInvalid(epService, "expression myindex {pointregionquadtree(0)} select * from SupportSpatialAABB(point(0, 0, filterindex:myindex).inside(rectangle(x, y, width, height)))", "Failed to validate filter expression 'point(0,0,filterindex:myindex()).in...(68 chars)': Index of type 'pointregionquadtree' requires at least 4 parameters but received 1 ["); SupportMessageAssertUtil.tryInvalid(epService, "expression myindex {pointregionquadtree(0,0,0,0)} select * from SupportSpatialAABB(point(0, 0, filterindex:myindex).inside(rectangle(x, y, width, height)))", "Failed to validate filter expression 'point(0,0,filterindex:myindex()).in...(68 chars)': Invalid value for index 'myindex' parameter 'width' received 0.0 and expected value>0"); SupportMessageAssertUtil.tryInvalid(epService, "expression myindex {pointregionquadtree(0,0,100,100).help()} select * from SupportSpatialAABB(point(0, 0, filterindex:myindex).inside(rectangle(x, y, width, height)))", "Failed to validate filter expression 'point(0,0,filterindex:myindex()).in...(68 chars)': Named parameter 'filterindex' invalid chained index expression"); // filter-not-optimizable SupportMessageAssertUtil.tryInvalid(epService, "expression myindex {pointregionquadtree(0, 0, 100, 100)} select * from SupportSpatialAABB(point(x, y, filterindex:myindex).inside(rectangle(x, y, width, height)))", "Invalid filter-indexable expression 'x' in respect to index 'myindex': expected either a constant, context-builtin or property from a previous pattern match [expression myindex {pointregionquadtree(0, 0, 100, 100)} select * from SupportSpatialAABB(point(x, y, filterindex:myindex).inside(rectangle(x, y, width, height)))]"); SupportMessageAssertUtil.tryInvalid(epService, "expression myindex {pointregionquadtree(0, 0, 100, 100)} select * from SupportSpatialAABB(point(0, 0, filterindex:myindex).inside(rectangle(0, y, width, height)))", "Invalid filter-index lookup expression '0' in respect to index 'myindex': expected an event property"); } private void runAssertionDocSample() throws Exception { String epl = "create table PointTable(pointId string primary key, px double, py double);\n" + "create index PointIndex on PointTable((px, py) pointregionquadtree(0, 0, 100, 100));\n" + "create schema RectangleEvent(rx double, ry double, w double, h double);\n" + "on RectangleEvent select pointId from PointTable where point(px, py).inside(rectangle(rx, ry, w, h));" + "expression myQuadtreeSettings { pointregionquadtree(0, 0, 100, 100) } \n" + "select * from SupportSpatialAABB(point(0, 0, filterindex:myQuadtreeSettings).inside(rectangle(x, y, width, height)));\n"; String deploymentId = epService.getEPAdministrator().getDeploymentAdmin().parseDeploy(epl).getDeploymentId(); epService.getEPAdministrator().getDeploymentAdmin().undeploy(deploymentId); } private void runAssertionEventIndexChoiceBetweenIndexTypes() throws Exception { String epl = "@Name('win') create window MyPointWindow#keepall as (id string, category string, px double, py double);\n" + "@Name('insert') insert into MyPointWindow select id, category, px, py from SupportSpatialPoint;\n" + "@Name('idx1') create index IdxHash on MyPointWindow(category);\n" + "@Name('idx2') create index IdxQuadtree on MyPointWindow((px, py) pointregionquadtree(0, 0, 100, 100));\n"; String deploymentId = epService.getEPAdministrator().getDeploymentAdmin().parseDeploy(epl).getDeploymentId(); sendPoint(epService, "P1", 10, 15, "X"); sendPoint(epService, "P2", 10, 15, "Y"); sendPoint(epService, "P3", 10, 15, "Z"); assertIndexChoice("", "IdxQuadtree"); assertIndexChoice("@Hint('index(IdxHash, bust)')", "IdxQuadtree"); epService.getEPAdministrator().getDeploymentAdmin().undeploy(deploymentId); } private void runAssertionEventIndexUnique() throws Exception { String epl = "@Name('win') create window MyPointWindow#keepall as (id string, px double, py double);\n" + "@Name('insert') insert into MyPointWindow select id, px, py from SupportSpatialPoint;\n" + "@Name('idx') create unique index Idx on MyPointWindow( (px, py) pointregionquadtree(0, 0, 100, 100));\n" + "@Name('out') on SupportSpatialAABB select mpw.id as c0 from MyPointWindow as mpw where point(px, py).inside(rectangle(x, y, width, height));\n"; String deploymentId = epService.getEPAdministrator().getDeploymentAdmin().parseDeploy(epl).getDeploymentId(); epService.getEPAdministrator().getStatement("out").addListener(listener); sendPoint(epService, "P1", 10, 15); try { sendPoint(epService, "P2", 10, 15); fail(); } catch (RuntimeException ex) { // we have a handler SupportMessageAssertUtil.assertMessage(ex, "Unexpected exception in statement 'win': Unique index violation, index 'Idx' is a unique index and key '(10.0,15.0)' already exists"); } epService.getEPAdministrator().getDeploymentAdmin().undeploy(deploymentId); } private void runAssertionEventIndexPerformance() throws Exception { String epl = "create window MyPointWindow#keepall as (id string, px double, py double);\n" + "insert into MyPointWindow select id, px, py from SupportSpatialPoint;\n" + "create index Idx on MyPointWindow( (px, py) pointregionquadtree(0, 0, 100, 100));\n" + "@Name('out') on SupportSpatialAABB select mpw.id as c0 from MyPointWindow as mpw where point(px, py).inside(rectangle(x, y, width, height));\n"; String deploymentId = epService.getEPAdministrator().getDeploymentAdmin().parseDeploy(epl).getDeploymentId(); epService.getEPAdministrator().getStatement("out").addListener(listener); for (int x = 0; x < 100; x++) { for (int y = 0; y < 100; y++) { epService.getEPRuntime().sendEvent(new SupportSpatialPoint(Integer.toString(x) + "_" + Integer.toString(y), (double) x, (double) y)); } } long start = System.currentTimeMillis(); for (int x = 0; x < 100; x++) { for (int y = 0; y < 100; y++) { epService.getEPRuntime().sendEvent(new SupportSpatialAABB("R", x, y, 0.5, 0.5)); assertEquals(Integer.toString(x) + "_" + Integer.toString(y), listener.assertOneGetNewAndReset().get("c0")); } } long delta = System.currentTimeMillis() - start; assertTrue("delta=" + delta, delta < 1000); epService.getEPAdministrator().getDeploymentAdmin().undeploy(deploymentId); } private void runAssertionEventIndexUnusedNamedWindowFireAndForget() throws Exception { String epl = "@Resilient create window PointWindow#keepall as (id string, px double, py double);\n" + "@Resilient create index MyIndex on PointWindow((px,py) pointregionquadtree(0,0,100,100,2,12));\n" + "@Resilient insert into PointWindow select id, px, py from SupportSpatialPoint;\n" + "@Resilient @name('out') on SupportSpatialAABB as aabb select pt.id as c0 from PointWindow as pt where point(px,py).inside(rectangle(x,y,width,height));\n"; String deploymentId = epService.getEPAdministrator().getDeploymentAdmin().parseDeploy(epl).getDeploymentId(); epService.getEPRuntime().executeQuery("delete from PointWindow where id='P1'"); epService.getEPAdministrator().getDeploymentAdmin().undeployRemove(deploymentId); } private void runAssertionEventIndexTableFireAndForget() { epService.getEPAdministrator().createEPL("create table MyTable(id string primary key, tx double, ty double)"); epService.getEPAdministrator().createEPL("insert into MyTable select id, px as tx, py as ty from SupportSpatialPoint"); epService.getEPRuntime().sendEvent(new SupportSpatialPoint("P1", 50d, 50d)); epService.getEPRuntime().sendEvent(new SupportSpatialPoint("P2", 49d, 49d)); epService.getEPAdministrator().createEPL("create index MyIdxWithExpr on MyTable( (tx, ty) pointregionquadtree(0, 0, 100, 100))"); EPOnDemandQueryResult result = epService.getEPRuntime().executeQuery(IndexBackingTableInfo.INDEX_CALLBACK_HOOK + "select id as c0 from MyTable where point(tx, ty).inside(rectangle(45, 45, 10, 10))"); SupportQueryPlanIndexHook.assertFAFAndReset("MyIdxWithExpr", "EventTableQuadTreePointRegionImpl"); EPAssertionUtil.assertPropsPerRowAnyOrder(result.getArray(), "c0".split(","), new Object[][]{{"P1"}, {"P2"}}); epService.getEPAdministrator().destroyAllStatements(); } private void runAssertionEventIndexExpression() { epService.getEPAdministrator().createEPL("create table MyTable(id string primary key, tx double, ty double)"); epService.getEPRuntime().executeQuery("insert into MyTable values ('P1', 50, 30)"); epService.getEPRuntime().executeQuery("insert into MyTable values ('P2', 50, 28)"); epService.getEPRuntime().executeQuery("insert into MyTable values ('P3', 50, 30)"); epService.getEPRuntime().executeQuery("insert into MyTable values ('P4', 49, 29)"); epService.getEPAdministrator().createEPL("create index MyIdxWithExpr on MyTable( (tx*10, ty*10) pointregionquadtree(0, 0, 1000, 1000))"); String eplOne = IndexBackingTableInfo.INDEX_CALLBACK_HOOK + "on SupportSpatialAABB select tbl.id as c0 from MyTable as tbl where point(tx, ty).inside(rectangle(x, y, width, height))"; EPStatement statementOne = epService.getEPAdministrator().createEPL(eplOne); statementOne.addListener(listener); SupportQueryPlanIndexHook.assertOnExprTableAndReset(null, null); assertRectanglesManyRow(epService, listener, BOXES, "P4", "P1,P2,P3", null, null, "P1,P2,P3,P4"); statementOne.destroy(); String eplTwo = IndexBackingTableInfo.INDEX_CALLBACK_HOOK + "on SupportSpatialAABB select tbl.id as c0 from MyTable as tbl where point(tx*10, tbl.ty*10).inside(rectangle(x, y, width, height))"; EPStatement statementTwo = epService.getEPAdministrator().createEPL(eplTwo); statementTwo.addListener(listener); SupportQueryPlanIndexHook.assertOnExprTableAndReset("MyIdxWithExpr", "non-unique hash={} btree={} advanced={pointregionquadtree(tx*10,ty*10)}"); assertRectanglesManyRow(epService, listener, BOXES, null, null, null, null, null); assertRectanglesManyRow(epService, listener, Collections.singletonList(new BoundingBox(500, 300, 501, 301)), "P1,P3"); statementTwo.destroy(); epService.getEPAdministrator().destroyAllStatements(); } private void runAssertionEventIndexChoiceOfTwo() throws Exception { String epl = "create table MyPointTable(" + " id string primary key," + " x1 double, y1 double, \n" + " x2 double, y2 double);\n" + "create index Idx1 on MyPointTable( (x1, y1) pointregionquadtree(0, 0, 100, 100));\n" + "create index Idx2 on MyPointTable( (x2, y2) pointregionquadtree(0, 0, 100, 100));\n" + "on SupportSpatialDualPoint dp merge MyPointTable t where dp.id = t.id when not matched then insert select dp.id as id,x1,y1,x2,y2;\n"; String deploymentId = epService.getEPAdministrator().getDeploymentAdmin().parseDeploy(epl).getDeploymentId(); String textOne = IndexBackingTableInfo.INDEX_CALLBACK_HOOK + "on SupportSpatialAABB select tbl.id as c0 from MyPointTable as tbl where point(x1, y1).inside(rectangle(x, y, width, height))"; EPStatement statementOne = epService.getEPAdministrator().createEPL(textOne); statementOne.addListener(listener); SupportQueryPlanIndexHook.assertOnExprTableAndReset("Idx1", "non-unique hash={} btree={} advanced={pointregionquadtree(x1,y1)}"); String textTwo = IndexBackingTableInfo.INDEX_CALLBACK_HOOK + "on SupportSpatialAABB select tbl.id as c0 from MyPointTable as tbl where point(tbl.x2, y2).inside(rectangle(x, y, width, height))"; EPStatement statementTwo = epService.getEPAdministrator().createEPL(textTwo); statementTwo.addListener(listener); SupportQueryPlanIndexHook.assertOnExprTableAndReset("Idx2", "non-unique hash={} btree={} advanced={pointregionquadtree(x2,y2)}"); epService.getEPRuntime().sendEvent(new SupportSpatialDualPoint("P1", 10, 10, 60, 60)); epService.getEPRuntime().sendEvent(new SupportSpatialDualPoint("P2", 55, 20, 4, 88)); assertRectanglesSingleValue(epService, listener, BOXES, "P1", "P2", "P2", "P1", "P1"); statementOne.destroy(); statementTwo.destroy(); epService.getEPAdministrator().getDeploymentAdmin().undeploy(deploymentId); } private void runAssertionEventIndexSubqNamedWindowIndexShare() throws Exception { String epl = "@Hint('enable_window_subquery_indexshare') create window MyWindow#length(5) as select * from SupportSpatialPoint;\n" + "create index MyIndex on MyWindow((px,py) pointregionquadtree(0,0,100,100));\n" + "insert into MyWindow select * from SupportSpatialPoint;\n" + IndexBackingTableInfo.INDEX_CALLBACK_HOOK + "@name('out') select (select id from MyWindow as mw where point(mw.px,mw.py).inside(rectangle(aabb.x,aabb.y,aabb.width,aabb.height))).aggregate('', \n" + " (result, item) => result || (case when result='' then '' else ',' end) || item) as c0 from SupportSpatialAABB aabb"; DeploymentResult deploymentResult = epService.getEPAdministrator().getDeploymentAdmin().parseDeploy(epl); epService.getEPAdministrator().getStatement("out").addListener(listener); QueryPlanIndexDescSubquery subquery = SupportQueryPlanIndexHook.assertSubqueryAndReset(); assertEquals("non-unique hash={} btree={} advanced={pointregionquadtree(px,py)}", subquery.getTables()[0].getIndexDesc()); assertEquals("MyIndex", subquery.getTables()[0].getIndexName()); sendPoint(epService, "P1", 10, 40); assertRectanglesSingleValue(epService, listener, BOXES, "P1", "", "", "", ""); epService.getEPAdministrator().getDeploymentAdmin().undeploy(deploymentResult.getDeploymentId()); } private void runAssertionEventIndexUnusedOnTrigger() throws Exception { String epl = "create window MyWindow#length(5) as select * from SupportSpatialPoint;\n" + "create index MyIndex on MyWindow((px,py) pointregionquadtree(0,0,100,100));\n" + "insert into MyWindow select * from SupportSpatialPoint;\n"; DeploymentResult deploymentResult = epService.getEPAdministrator().getDeploymentAdmin().parseDeploy(epl); sendPoint(epService, "P1", 5, 5); sendPoint(epService, "P2", 55, 60); runIndexUnusedConstantsOnly(); runIndexUnusedPointValueDepends(); runIndexUnusedRectValueDepends(); epService.getEPAdministrator().getDeploymentAdmin().undeploy(deploymentResult.getDeploymentId()); } private void runIndexUnusedRectValueDepends() { String epl = IndexBackingTableInfo.INDEX_CALLBACK_HOOK + "@name('out') on SupportSpatialAABB as aabb select points.id as c0 " + "from MyWindow as points where point(px, py).inside(rectangle(px,py,1,1))"; EPStatement stmt = epService.getEPAdministrator().createEPL(epl); stmt.addListener(listener); SupportQueryPlanIndexHook.assertOnExprTableAndReset(null, null); assertRectanglesManyRow(epService, listener, BOXES, "P1,P2", "P1,P2", "P1,P2", "P1,P2", "P1,P2"); stmt.destroy(); } private void runIndexUnusedPointValueDepends() { String epl = IndexBackingTableInfo.INDEX_CALLBACK_HOOK + "@name('out') on SupportSpatialAABB as aabb select points.id as c0 " + "from MyWindow as points where point(px + x, py + y).inside(rectangle(x,y,width,height))"; EPStatement stmt = epService.getEPAdministrator().createEPL(epl); stmt.addListener(listener); SupportQueryPlanIndexHook.assertOnExprTableAndReset(null, null); assertRectanglesManyRow(epService, listener, BOXES, "P1", "P1", "P1", "P1", "P1"); stmt.destroy(); } private void runIndexUnusedConstantsOnly() { String epl = IndexBackingTableInfo.INDEX_CALLBACK_HOOK + "@name('out') on SupportSpatialAABB as aabb select points.id as c0 " + "from MyWindow as points where point(0, 0).inside(rectangle(x,y,width,height))"; EPStatement stmt = epService.getEPAdministrator().createEPL(epl); stmt.addListener(listener); SupportQueryPlanIndexHook.assertOnExprTableAndReset(null, null); assertRectanglesManyRow(epService, listener, BOXES, "P1,P2", null, null, null, null); stmt.destroy(); } private void runAssertionInvalidMethod() { SupportMessageAssertUtil.tryInvalid(epService, "select * from MyEventRectangleWithOffset(point('a', 0).inside(rectangle(0, 0, 0, 0)))", "Failed to validate filter expression 'point(\"a\",0).inside(rectangle(0,0,0,0))': Error validating left-hand-side function 'point', expected a number-type result for expression parameter 0 but received java.lang.String"); SupportMessageAssertUtil.tryInvalid(epService, "select * from MyEventRectangleWithOffset(point(0).inside(rectangle(0, 0, 0, 0)))", "Failed to validate filter expression 'point(0).inside(rectangle(0,0,0,0))': Error validating left-hand-side method 'point', expected 2 parameters but received 1 parameters"); SupportMessageAssertUtil.tryInvalid(epService, "select * from MyEventRectangleWithOffset(point(0,0).inside(rectangle('a', 0, 0, 0)))", "Failed to validate filter expression 'point(0,0).inside(rectangle(\"a\",0,0,0))': Error validating right-hand-side function 'rectangle', expected a number-type result for expression parameter 0 but received java.lang.String"); SupportMessageAssertUtil.tryInvalid(epService, "select * from MyEventRectangleWithOffset(point(0,0).inside(rectangle(0)))", "Failed to validate filter expression 'point(0,0).inside(rectangle(0))': Error validating right-hand-side function 'rectangle', expected 4 parameters but received 1 parameters"); SupportMessageAssertUtil.tryInvalid(epService, "select * from MyEventRectangleWithOffset(point(0,0).inside(0))", "Failed to validate filter expression 'point(0,0).inside(0)': point.inside requires a single rectangle as parameter"); } private void runAssertionEventIndexUnindexed() { EPStatement stmt = epService.getEPAdministrator().createEPL("select point(xOffset, yOffset).inside(rectangle(x, y, width, height)) as c0 from MyEventRectangleWithOffset"); stmt.addListener(listener); sendAssert(epService, listener, 1, 1, 0, 0, 2, 2, true); sendAssert(epService, listener, 3, 1, 0, 0, 2, 2, false); sendAssert(epService, listener, 2, 1, 0, 0, 2, 2, false); sendAssert(epService, listener, 1, 3, 0, 0, 2, 2, false); sendAssert(epService, listener, 1, 2, 0, 0, 2, 2, false); sendAssert(epService, listener, 0, 0, 1, 1, 2, 2, false); sendAssert(epService, listener, 1, 0, 1, 1, 2, 2, false); sendAssert(epService, listener, 0, 1, 1, 1, 2, 2, false); sendAssert(epService, listener, 1, 1, 1, 1, 2, 2, true); sendAssert(epService, listener, 2.9999, 2.9999, 1, 1, 2, 2, true); sendAssert(epService, listener, 3, 2.9999, 1, 1, 2, 2, false); sendAssert(epService, listener, 2.9999, 3, 1, 1, 2, 2, false); sendAssertWNull(epService, listener, null, 0d, 0d, 0d, 0d, 0d, null); sendAssertWNull(epService, listener, 0d, 0d, 0d, null, 0d, 0d, null); epService.getEPAdministrator().destroyAllStatements(); } private void runAssertionEventIndexOnTriggerContextParameterized() throws Exception { String epl = "create context CtxBox initiated by MyEventRectangleWithOffset box;\n" + "context CtxBox create window MyWindow#keepall as SupportSpatialPoint;\n" + "context CtxBox create index MyIndex on MyWindow((px+context.box.xOffset, py+context.box.yOffset) pointregionquadtree(context.box.x, context.box.y, context.box.width, context.box.height));\n" + "context CtxBox on SupportSpatialPoint(category = context.box.id) merge MyWindow when not matched then insert select *;\n" + "@name('out') context CtxBox on SupportSpatialAABB(category = context.box.id) aabb " + " select points.id as c0 from MyWindow points where point(px, py).inside(rectangle(x, y, width, height))"; DeploymentResult deploymentResult = epService.getEPAdministrator().getDeploymentAdmin().parseDeploy(epl); epService.getEPAdministrator().getStatement("out").addListener(listener); epService.getEPRuntime().sendEvent(new MyEventRectangleWithOffset("NW", 0d, 0d, 0d, 0d, 50d, 50d)); epService.getEPRuntime().sendEvent(new MyEventRectangleWithOffset("SE", 0d, 0d, 50d, 50d, 50d, 50d)); sendPoint(epService, "P1", 60, 90, "SE"); sendPoint(epService, "P2", 5, 20, "NW"); epService.getEPRuntime().sendEvent(new SupportSpatialAABB("R1", 60, 60, 40, 40, "SE")); assertEquals("P1", listener.assertOneGetNewAndReset().get("c0")); epService.getEPRuntime().sendEvent(new SupportSpatialAABB("R2", 0, 0, 5.0001, 20.0001, "NW")); assertEquals("P2", listener.assertOneGetNewAndReset().get("c0")); epService.getEPRuntime().sendEvent(new SupportSpatialAABB("R3", 0, 0, 5, 30, "NW")); epService.getEPRuntime().sendEvent(new SupportSpatialAABB("R3", 0, 0, 30, 20, "NW")); assertFalse(listener.isInvoked()); epService.getEPAdministrator().getDeploymentAdmin().undeploy(deploymentResult.getDeploymentId()); } private void runAssertionEventIndexOnTriggerNWInsertRemove(boolean soda) { SupportModelHelper.createByCompileOrParse(epService, soda, "create window MyWindow#length(5) as select * from SupportSpatialPoint"); SupportModelHelper.createByCompileOrParse(epService, soda, "create index MyIndex on MyWindow((px,py) pointregionquadtree(0,0,100,100))"); SupportModelHelper.createByCompileOrParse(epService, soda, "insert into MyWindow select * from SupportSpatialPoint"); String epl = IndexBackingTableInfo.INDEX_CALLBACK_HOOK + " on SupportSpatialAABB as aabb " + "select points.id as c0 from MyWindow as points where point(px,py).inside(rectangle(x,y,width,height))"; EPStatement stmt = SupportModelHelper.createByCompileOrParse(epService, soda, epl); stmt.addListener(listener); SupportQueryPlanIndexHook.assertOnExprTableAndReset("MyIndex", "non-unique hash={} btree={} advanced={pointregionquadtree(px,py)}"); sendPoint(epService, "P1", 10, 40); assertRectanglesManyRow(epService, listener, BOXES, "P1", null, null, null, null); sendPoint(epService, "P2", 80, 80); assertRectanglesManyRow(epService, listener, BOXES, "P1", null, null, "P2", null); sendPoint(epService, "P3", 10, 40); assertRectanglesManyRow(epService, listener, BOXES, "P1,P3", null, null, "P2", null); sendPoint(epService, "P4", 60, 40); assertRectanglesManyRow(epService, listener, BOXES, "P1,P3", "P4", null, "P2", "P4"); sendPoint(epService, "P5", 20, 75); assertRectanglesManyRow(epService, listener, BOXES, "P1,P3", "P4", "P5", "P2", "P4"); sendPoint(epService, "P6", 50, 50); assertRectanglesManyRow(epService, listener, BOXES, "P3", "P4", "P5", "P2,P6", "P4,P6"); sendPoint(epService, "P7", 0, 0); assertRectanglesManyRow(epService, listener, BOXES, "P3,P7", "P4", "P5", "P6", "P4,P6"); sendPoint(epService, "P8", 99.999, 0); assertRectanglesManyRow(epService, listener, BOXES, "P7", "P4,P8", "P5", "P6", "P4,P6"); sendPoint(epService, "P9", 0, 99.999); assertRectanglesManyRow(epService, listener, BOXES, "P7", "P8", "P5,P9", "P6", "P6"); sendPoint(epService, "P10", 99.999, 99.999); assertRectanglesManyRow(epService, listener, BOXES, "P7", "P8", "P9", "P6,P10", "P6"); sendPoint(epService, "P11", 0, 0); assertRectanglesManyRow(epService, listener, BOXES, "P7,P11", "P8", "P9", "P10", null); epService.getEPAdministrator().destroyAllStatements(); } private void runAssertionEventIndexOnTriggerTable() throws Exception { String epl = "create table MyPointTable(my_x double primary key, my_y double primary key, my_id string);\n" + "@Audit create index MyIndex on MyPointTable( (my_x, my_y) pointregionquadtree(0, 0, 100, 100));\n" + "on SupportSpatialPoint ssp merge MyPointTable where ssp.px = my_x and ssp.py = my_y when not matched then insert select px as my_x, py as my_y, id as my_id;\n" + IndexBackingTableInfo.INDEX_CALLBACK_HOOK + "@Audit @name('s0') on SupportSpatialAABB select my_id as c0 from MyPointTable as c0 where point(my_x, my_y).inside(rectangle(x, y, width, height))"; String deploymentId = epService.getEPAdministrator().getDeploymentAdmin().parseDeploy(epl).getDeploymentId(); EPStatement stmt = epService.getEPAdministrator().getStatement("s0"); stmt.addListener(listener); SupportQueryPlanIndexHook.assertOnExprTableAndReset("MyIndex", "non-unique hash={} btree={} advanced={pointregionquadtree(my_x,my_y)}"); sendPoint(epService, "P1", 55, 45); assertRectanglesManyRow(epService, listener, BOXES, null, "P1", null, null, "P1"); sendPoint(epService, "P2", 45, 45); assertRectanglesManyRow(epService, listener, BOXES, "P2", "P1", null, null, "P1,P2"); sendPoint(epService, "P3", 55, 55); assertRectanglesManyRow(epService, listener, BOXES, "P2", "P1", null, "P3", "P1,P2,P3"); epService.getEPRuntime().executeQuery("delete from MyPointTable where my_x = 55 and my_y = 45"); sendPoint(epService, "P4", 45, 55); assertRectanglesManyRow(epService, listener, BOXES, "P2", null, "P4", "P3", "P2,P3,P4"); epService.getEPAdministrator().getDeploymentAdmin().undeploy(deploymentId); } private void runAssertionInvalidEventIndexRuntime() throws Exception { String epl = "@name('mywindow') create window PointWindow#keepall as SupportSpatialPoint;\n" + "insert into PointWindow select * from SupportSpatialPoint;\n" + "create index MyIndex on PointWindow((px, py) pointregionquadtree(0, 0, 100, 100));\n"; epService.getEPAdministrator().getDeploymentAdmin().parseDeploy(epl); try { epService.getEPRuntime().sendEvent(new SupportSpatialPoint("E1", null, null)); } catch (Exception ex) { SupportMessageAssertUtil.assertMessage(ex, "Unexpected exception in statement 'mywindow': Invalid value for index 'MyIndex' column 'x' received null and expected non-null"); } try { epService.getEPRuntime().sendEvent(new SupportSpatialPoint("E1", 200d, 200d)); } catch (Exception ex) { SupportMessageAssertUtil.assertMessage(ex, "Unexpected exception in statement 'mywindow': Invalid value for index 'MyIndex' column '(x,y)' received (200.0,200.0) and expected a value within index bounding box (range-end-non-inclusive) {minX=0.0, minY=0.0, maxX=100.0, maxY=100.0}"); } } private void runAssertionInvalidEventIndexCreate() { epService.getEPAdministrator().createEPL("create window MyWindow#keepall as SupportSpatialPoint"); // invalid number of columns SupportMessageAssertUtil.tryInvalid(epService, "create index MyIndex on MyWindow(px pointregionquadtree(0, 0, 100, 100))", "Error starting statement: Index of type 'pointregionquadtree' requires 2 expressions as index columns but received 1"); // invalid column type SupportMessageAssertUtil.tryInvalid(epService, "create index MyIndex on MyWindow((id, py) pointregionquadtree(0, 0, 100, 100))", "Error starting statement: Index of type 'pointregionquadtree' for column 0 that is providing x-values expecting type java.lang.Number but received type java.lang.String"); SupportMessageAssertUtil.tryInvalid(epService, "create index MyIndex on MyWindow((px, id) pointregionquadtree(0, 0, 100, 100))", "Error starting statement: Index of type 'pointregionquadtree' for column 1 that is providing y-values expecting type java.lang.Number but received type java.lang.String"); // invalid expressions for column or parameter SupportMessageAssertUtil.tryInvalid(epService, "create index MyIndex on MyWindow((dummy, dummy2) pointregionquadtree(0, 0, 100, 100))", "Error starting statement: Failed to validate create-index index-column expression 'dummy': Property named 'dummy' is not valid in any stream"); SupportMessageAssertUtil.tryInvalid(epService, "create index MyIndex on MyWindow((px, py) pointregionquadtree(dummy, 0, 100, 100))", "Error starting statement: Failed to validate create-index index-parameter expression 'dummy': Property named 'dummy' is not valid in any stream"); // invalid property use in parameter SupportMessageAssertUtil.tryInvalid(epService, "create index MyIndex on MyWindow((px, py) pointregionquadtree(px, 0, 100, 100))", "Error starting statement: Index parameters may not refer to event properties"); // invalid number of parameters SupportMessageAssertUtil.tryInvalid(epService, "create index MyIndex on MyWindow((px, py) pointregionquadtree)", "Error starting statement: Index of type 'pointregionquadtree' requires at least 4 parameters but received 0"); SupportMessageAssertUtil.tryInvalid(epService, "create index MyIndex on MyWindow((px, py) pointregionquadtree('a'))", "Error starting statement: Index of type 'pointregionquadtree' requires at least 4 parameters but received 1"); SupportMessageAssertUtil.tryInvalid(epService, "create index MyIndex on MyWindow((px, py) pointregionquadtree(0, 0, 0, 0, 0, 0, 0))", "Error starting statement: Index of type 'pointregionquadtree' requires at least 4 parameters but received 7"); // invalid parameter type SupportMessageAssertUtil.tryInvalid(epService, "create index MyIndex on MyWindow((px, py) pointregionquadtree('a', 0, 100, 100))", "Error starting statement: Index of type 'pointregionquadtree' for parameter 0 that is providing xMin-values expecting type java.lang.Number but received type java.lang.String"); SupportMessageAssertUtil.tryInvalid(epService, "create index MyIndex on MyWindow((px, py) pointregionquadtree(0, 'a', 100, 100))", "Error starting statement: Index of type 'pointregionquadtree' for parameter 1 that is providing yMin-values expecting type java.lang.Number but received type java.lang.String"); SupportMessageAssertUtil.tryInvalid(epService, "create index MyIndex on MyWindow((px, py) pointregionquadtree(0, 0, 'a', 100))", "Error starting statement: Index of type 'pointregionquadtree' for parameter 2 that is providing width-values expecting type java.lang.Number but received type java.lang.String"); SupportMessageAssertUtil.tryInvalid(epService, "create index MyIndex on MyWindow((px, py) pointregionquadtree(0, 0, 100, 'a'))", "Error starting statement: Index of type 'pointregionquadtree' for parameter 3 that is providing height-values expecting type java.lang.Number but received type java.lang.String"); SupportMessageAssertUtil.tryInvalid(epService, "create index MyIndex on MyWindow((px, py) pointregionquadtree(0, 0, 100, 100, 'a'))", "Error starting statement: Index of type 'pointregionquadtree' for parameter 4 that is providing leafCapacity-values expecting type java.lang.Integer but received type java.lang.String"); SupportMessageAssertUtil.tryInvalid(epService, "create index MyIndex on MyWindow((px, py) pointregionquadtree(0, 0, 100, 100, 1, 'a'))", "Error starting statement: Index of type 'pointregionquadtree' for parameter 5 that is providing maxTreeHeight-values expecting type java.lang.Integer but received type java.lang.String"); // invalid parameter value SupportMessageAssertUtil.tryInvalid(epService, "create index MyIndex on MyWindow((px, py) pointregionquadtree(cast(null, double), 0, 0, 0))", "Unexpected exception starting statement: Invalid value for index 'MyIndex' parameter 'xMin' received null and expected non-null"); SupportMessageAssertUtil.tryInvalid(epService, "create index MyIndex on MyWindow((py, px) pointregionquadtree(0, 0, -100, 0))", "Unexpected exception starting statement: Invalid value for index 'MyIndex' parameter 'width' received -100.0 and expected value>0"); SupportMessageAssertUtil.tryInvalid(epService, "create index MyIndex on MyWindow((py, px) pointregionquadtree(0, 0, 1, -200))", "Unexpected exception starting statement: Invalid value for index 'MyIndex' parameter 'height' received -200.0 and expected value>0"); SupportMessageAssertUtil.tryInvalid(epService, "create index MyIndex on MyWindow((py, px) pointregionquadtree(0, 0, 1, 1, -1))", "Unexpected exception starting statement: Invalid value for index 'MyIndex' parameter 'leafCapacity' received -1 and expected value>=1"); SupportMessageAssertUtil.tryInvalid(epService, "create index MyIndex on MyWindow((py, px) pointregionquadtree(0, 0, 1, 1, 10, -1))", "Unexpected exception starting statement: Invalid value for index 'MyIndex' parameter 'maxTreeHeight' received -1 and expected value>=2"); // same index twice, by-name and by-columns epService.getEPAdministrator().createEPL("create window SomeWindow#keepall as SupportSpatialPoint"); epService.getEPAdministrator().createEPL("create index SomeWindowIdx1 on SomeWindow((px, py) pointregionquadtree(0, 0, 1, 1))"); SupportMessageAssertUtil.tryInvalid(epService, "create index SomeWindowIdx2 on SomeWindow((px, py) pointregionquadtree(0, 0, 1, 1))", "Error starting statement: An index for the same columns already exists"); SupportMessageAssertUtil.tryInvalid(epService, "create index SomeWindowIdx1 on SomeWindow((py, px) pointregionquadtree(0, 0, 1, 1))", "Error starting statement: An index by name 'SomeWindowIdx1' already exists"); // non-plain column or parameter expressions SupportMessageAssertUtil.tryInvalid(epService, "create index MyIndexInv on MyWindow((sum(px), py) pointregionquadtree(0, 0, 1, 1))", "Error starting statement: Invalid create-index index-column expression 'sum(px)': Aggregation, sub-select, previous or prior functions are not supported in this context"); SupportMessageAssertUtil.tryInvalid(epService, "create index MyIndexInv on MyWindow((px, py) pointregionquadtree(count(*), 0, 1, 1))", "Error starting statement: Invalid create-index index-parameter expression 'count(*)': Aggregation, sub-select, previous or prior functions are not supported in this context"); epService.getEPAdministrator().destroyAllStatements(); } private void runAssertionFilterIndexUnoptimized() { EPStatement stmt = epService.getEPAdministrator().createEPL("select * from SupportSpatialAABB(point(5, 10).inside(rectangle(x, y, width, height)))"); stmt.addListener(listener); sendRectangle(epService, "R1", 0, 0, 5, 10); sendRectangle(epService, "R2", 4, 3, 2, 20); assertEquals("R2", listener.assertOneGetNewAndReset().get("id")); epService.getEPAdministrator().destroyAllStatements(); } private void runAssertionFilterIndexPerfStatement() { EPPreparedStatement prepared = epService.getEPAdministrator().prepareEPL("expression myindex {pointregionquadtree(0, 0, 100, 100)}" + "select * from SupportSpatialAABB(point(?, ?, filterindex:myindex).inside(rectangle(x, y, width, height)))"); for (int x = 0; x < 100; x++) { for (int y = 0; y < 20; y++) { prepared.setObject(1, x); prepared.setObject(2, y); epService.getEPAdministrator().create(prepared).addListener(listener); } } sendAssertSpatialAABB(epService, listener, 100, 20, 1000); epService.getEPAdministrator().destroyAllStatements(); } private void runAssertionFilterIndexPerfPattern() { EPStatement stmt = epService.getEPAdministrator().createEPL("expression myindex {pointregionquadtree(0, 0, 100, 100)}" + "select * from pattern [every p=SupportSpatialPoint -> SupportSpatialAABB(point(p.px, p.py, filterindex:myindex).inside(rectangle(x, y, width, height)))]"); stmt.addListener(listener); sendSpatialPoints(epService, 100, 100); sendAssertSpatialAABB(epService, listener, 100, 100, 1000); epService.getEPAdministrator().destroyAllStatements(); } private void runAssertionFilterIndexPerfContextPartition() { epService.getEPAdministrator().createEPL("create context PerPointCtx initiated by SupportSpatialPoint ssp"); EPStatement stmt = epService.getEPAdministrator().createEPL("expression myindex {pointregionquadtree(0, 0, 100, 100)}" + "context PerPointCtx select count(*) from SupportSpatialAABB(point(context.ssp.px, context.ssp.py, filterindex:myindex).inside(rectangle(x, y, width, height)))"); stmt.addListener(listener); sendSpatialPoints(epService, 100, 100); sendAssertSpatialAABB(epService, listener, 100, 100, 1000); epService.getEPAdministrator().destroyAllStatements(); } private void assertIndexChoice(String hint, String expectedIndexName) { String epl = IndexBackingTableInfo.INDEX_CALLBACK_HOOK + hint + "on SupportSpatialAABB as aabb select mpw.id as c0 from MyPointWindow as mpw " + "where aabb.category = mpw.category and point(px, py).inside(rectangle(x, y, width, height))\n"; EPStatement stmt = epService.getEPAdministrator().createEPL(epl); stmt.addListener(listener); QueryPlanIndexDescOnExpr plan = SupportQueryPlanIndexHook.assertOnExprAndReset(); assertEquals(expectedIndexName, plan.getTables()[0].getIndexName()); epService.getEPRuntime().sendEvent(new SupportSpatialAABB("R1", 9, 14, 1.0001, 1.0001, "Y")); assertEquals("P2", listener.assertOneGetNewAndReset().get("c0")); stmt.destroy(); } public static class MyEventRectangleWithOffset { private final String id; private final Double xOffset; private final Double yOffset; private final Double x; private final Double y; private final Double width; private final Double height; public MyEventRectangleWithOffset(String id, Double xOffset, Double yOffset, Double x, Double y, Double width, Double height) { this.id = id; this.xOffset = xOffset; this.yOffset = yOffset; this.x = x; this.y = y; this.width = width; this.height = height; } public String getId() { return id; } public Double getxOffset() { return xOffset; } public Double getyOffset() { return yOffset; } public Double getX() { return x; } public Double getY() { return y; } public Double getWidth() { return width; } public Double getHeight() { return height; } } }