|
70 | 70 | import org.janusgraph.diskstorage.indexing.IndexInformation; |
71 | 71 | import org.janusgraph.diskstorage.indexing.IndexProvider; |
72 | 72 | import org.janusgraph.diskstorage.indexing.IndexTransaction; |
| 73 | +import org.janusgraph.diskstorage.keycolumnvalue.scan.ScanJobFuture; |
73 | 74 | import org.janusgraph.diskstorage.log.kcvs.KCVSLog; |
74 | 75 | import org.janusgraph.diskstorage.util.time.TimestampProvider; |
75 | 76 | import org.janusgraph.example.GraphOfTheGodsFactory; |
|
83 | 84 | import org.janusgraph.graphdb.internal.ElementCategory; |
84 | 85 | import org.janusgraph.graphdb.internal.ElementLifeCycle; |
85 | 86 | import org.janusgraph.graphdb.internal.Order; |
| 87 | +import org.janusgraph.graphdb.internal.RelationCategory; |
86 | 88 | import org.janusgraph.graphdb.log.StandardTransactionLogProcessor; |
87 | 89 | import org.janusgraph.graphdb.query.index.ApproximateIndexSelectionStrategy; |
88 | 90 | import org.janusgraph.graphdb.query.index.BruteForceIndexSelectionStrategy; |
89 | 91 | import org.janusgraph.graphdb.query.index.ThresholdBasedIndexSelectionStrategy; |
90 | 92 | import org.janusgraph.graphdb.query.profile.QueryProfiler; |
| 93 | +import org.janusgraph.graphdb.query.vertex.BaseVertexCentricQuery; |
| 94 | +import org.janusgraph.graphdb.query.vertex.VertexCentricQueryBuilder; |
91 | 95 | import org.janusgraph.graphdb.tinkerpop.optimize.step.JanusGraphMixedIndexAggStep; |
92 | 96 | import org.janusgraph.graphdb.tinkerpop.optimize.step.JanusGraphStep; |
93 | 97 | import org.janusgraph.graphdb.tinkerpop.optimize.strategy.JanusGraphMixedIndexCountStrategy; |
|
106 | 110 | import org.slf4j.Logger; |
107 | 111 | import org.slf4j.LoggerFactory; |
108 | 112 |
|
| 113 | +import java.lang.reflect.InvocationTargetException; |
| 114 | +import java.lang.reflect.Method; |
109 | 115 | import java.time.Duration; |
110 | 116 | import java.time.Instant; |
111 | 117 | import java.time.temporal.ChronoUnit; |
@@ -1445,6 +1451,199 @@ public void testCompositeVsMixedIndexing() { |
1445 | 1451 | assertTrue(tx.traversal().V().has("intId2", 234).hasNext()); |
1446 | 1452 | } |
1447 | 1453 |
|
| 1454 | + @Test |
| 1455 | + public void testIndexInlineProperties() throws NoSuchMethodException { |
| 1456 | + |
| 1457 | + clopen(option(FORCE_INDEX_USAGE), true); |
| 1458 | + |
| 1459 | + final PropertyKey idKey = makeKey("id", Integer.class); |
| 1460 | + final PropertyKey nameKey = makeKey("name", String.class); |
| 1461 | + final PropertyKey cityKey = makeKey("city", String.class); |
| 1462 | + |
| 1463 | + mgmt.buildIndex("composite", Vertex.class) |
| 1464 | + .addKey(idKey) |
| 1465 | + .addInlinePropertyKey(nameKey) |
| 1466 | + .buildCompositeIndex(); |
| 1467 | + |
| 1468 | + finishSchema(); |
| 1469 | + |
| 1470 | + String name = "Mizar"; |
| 1471 | + String city = "Chicago"; |
| 1472 | + tx.addVertex("id", 100, "name", name, "city", city); |
| 1473 | + tx.commit(); |
| 1474 | + |
| 1475 | + tx = graph.buildTransaction() |
| 1476 | + .propertyPrefetching(false) //this is important |
| 1477 | + .start(); |
| 1478 | + |
| 1479 | + Method m = VertexCentricQueryBuilder.class.getSuperclass().getDeclaredMethod("constructQuery", RelationCategory.class); |
| 1480 | + m.setAccessible(true); |
| 1481 | + |
| 1482 | + CacheVertex v = (CacheVertex) (tx.traversal().V().has("id", 100).next()); |
| 1483 | + |
| 1484 | + verifyPropertyLoaded(v, "name", true, m); |
| 1485 | + verifyPropertyLoaded(v, "city", false, m); |
| 1486 | + |
| 1487 | + assertEquals(name, v.value("name")); |
| 1488 | + assertEquals(city, v.value("city")); |
| 1489 | + } |
| 1490 | + |
| 1491 | + @Test |
| 1492 | + public void testIndexInlinePropertiesReindex() throws NoSuchMethodException, InterruptedException { |
| 1493 | + clopen(option(FORCE_INDEX_USAGE), true); |
| 1494 | + |
| 1495 | + PropertyKey idKey = makeKey("id", Integer.class); |
| 1496 | + PropertyKey nameKey = makeKey("name", String.class); |
| 1497 | + PropertyKey cityKey = makeKey("city", String.class); |
| 1498 | + |
| 1499 | + mgmt.buildIndex("composite", Vertex.class) |
| 1500 | + .addKey(cityKey) |
| 1501 | + .buildCompositeIndex(); |
| 1502 | + |
| 1503 | + finishSchema(); |
| 1504 | + |
| 1505 | + String city = "Chicago"; |
| 1506 | + for (int i = 0; i < 3; i++) { |
| 1507 | + tx.addVertex("id", i, "name", "name" + i, "city", city); |
| 1508 | + } |
| 1509 | + |
| 1510 | + tx.commit(); |
| 1511 | + |
| 1512 | + tx = graph.buildTransaction() |
| 1513 | + .propertyPrefetching(false) //this is important |
| 1514 | + .start(); |
| 1515 | + |
| 1516 | + Method m = VertexCentricQueryBuilder.class.getSuperclass().getDeclaredMethod("constructQuery", RelationCategory.class); |
| 1517 | + m.setAccessible(true); |
| 1518 | + |
| 1519 | + List<Vertex> vertices = tx.traversal().V().has("city", city).toList(); |
| 1520 | + vertices.stream() |
| 1521 | + .map(v -> (CacheVertex) v) |
| 1522 | + .forEach(v -> verifyPropertyLoaded(v, "name", false, m)); |
| 1523 | + |
| 1524 | + tx.commit(); |
| 1525 | + |
| 1526 | + //Include inlined property |
| 1527 | + JanusGraphIndex index = mgmt.getGraphIndex("composite"); |
| 1528 | + nameKey = mgmt.getPropertyKey("name"); |
| 1529 | + mgmt.addInlinePropertyKey(index, nameKey); |
| 1530 | + finishSchema(); |
| 1531 | + |
| 1532 | + //Reindex |
| 1533 | + index = mgmt.getGraphIndex("composite"); |
| 1534 | + ScanJobFuture scanJobFuture = mgmt.updateIndex(index, SchemaAction.REINDEX); |
| 1535 | + finishSchema(); |
| 1536 | + |
| 1537 | + while (!scanJobFuture.isDone()) { |
| 1538 | + Thread.sleep(1000); |
| 1539 | + } |
| 1540 | + |
| 1541 | + //Try query now |
| 1542 | + tx = graph.buildTransaction() |
| 1543 | + .propertyPrefetching(false) //this is important |
| 1544 | + .start(); |
| 1545 | + |
| 1546 | + List<Vertex> vertices2 = tx.traversal().V().has("city", city).toList(); |
| 1547 | + vertices2.stream() |
| 1548 | + .map(v -> (CacheVertex) v) |
| 1549 | + .forEach(v -> verifyPropertyLoaded(v, "name", true, m)); |
| 1550 | + |
| 1551 | + tx.commit(); |
| 1552 | + } |
| 1553 | + |
| 1554 | + @Test |
| 1555 | + public void testIndexInlinePropertiesUpdate() { |
| 1556 | + |
| 1557 | + clopen(option(FORCE_INDEX_USAGE), true); |
| 1558 | + |
| 1559 | + final PropertyKey idKey = makeKey("id", Integer.class); |
| 1560 | + final PropertyKey nameKey = makeKey("name", String.class); |
| 1561 | + final PropertyKey cityKey = makeKey("city", String.class); |
| 1562 | + |
| 1563 | + mgmt.buildIndex("composite", Vertex.class) |
| 1564 | + .addKey(idKey) |
| 1565 | + .addInlinePropertyKey(nameKey) |
| 1566 | + .buildCompositeIndex(); |
| 1567 | + |
| 1568 | + finishSchema(); |
| 1569 | + |
| 1570 | + String name1 = "Mizar"; |
| 1571 | + String name2 = "Alcor"; |
| 1572 | + |
| 1573 | + String city = "Chicago"; |
| 1574 | + tx.addVertex("id", 100, "name", name1, "city", city); |
| 1575 | + tx.addVertex("id", 200, "name", name2, "city", city); |
| 1576 | + tx.commit(); |
| 1577 | + |
| 1578 | + tx = graph.buildTransaction() |
| 1579 | + .propertyPrefetching(false) //this is important |
| 1580 | + .start(); |
| 1581 | + |
| 1582 | + Vertex v = (tx.traversal().V().has("id", 100).next()); |
| 1583 | + assertEquals(name1, v.value("name")); |
| 1584 | + |
| 1585 | + //Update inlined property |
| 1586 | + v.property("name", "newName"); |
| 1587 | + tx.commit(); |
| 1588 | + |
| 1589 | + tx = graph.buildTransaction() |
| 1590 | + .propertyPrefetching(false) //this is important |
| 1591 | + .start(); |
| 1592 | + |
| 1593 | + v = (tx.traversal().V().has("id", 100).next()); |
| 1594 | + assertEquals("newName", v.value("name")); |
| 1595 | + } |
| 1596 | + |
| 1597 | + @Test |
| 1598 | + public void testIndexInlinePropertiesLimit() throws NoSuchMethodException { |
| 1599 | + |
| 1600 | + clopen(option(FORCE_INDEX_USAGE), true); |
| 1601 | + |
| 1602 | + final PropertyKey nameKey = makeKey("name", String.class); |
| 1603 | + final PropertyKey cityKey = makeKey("city", String.class); |
| 1604 | + |
| 1605 | + mgmt.buildIndex("composite", Vertex.class) |
| 1606 | + .addKey(cityKey) |
| 1607 | + .addInlinePropertyKey(nameKey) |
| 1608 | + .buildCompositeIndex(); |
| 1609 | + |
| 1610 | + finishSchema(); |
| 1611 | + |
| 1612 | + String city = "Chicago"; |
| 1613 | + for (int i = 0; i < 10; i++) { |
| 1614 | + String name = "name_" + i; |
| 1615 | + tx.addVertex("name", name, "city", city); |
| 1616 | + } |
| 1617 | + tx.commit(); |
| 1618 | + |
| 1619 | + tx = graph.buildTransaction() |
| 1620 | + .propertyPrefetching(false) //this is important |
| 1621 | + .start(); |
| 1622 | + |
| 1623 | + Method m = VertexCentricQueryBuilder.class.getSuperclass().getDeclaredMethod("constructQuery", RelationCategory.class); |
| 1624 | + m.setAccessible(true); |
| 1625 | + |
| 1626 | + List<Vertex> vertices = tx.traversal().V().has("city", city).limit(3).toList(); |
| 1627 | + assertEquals(3, vertices.size()); |
| 1628 | + vertices.stream().map(v -> (CacheVertex) v).forEach(v -> { |
| 1629 | + verifyPropertyLoaded(v, "name", true, m); |
| 1630 | + verifyPropertyLoaded(v, "city", false, m); |
| 1631 | + }); |
| 1632 | + } |
| 1633 | + |
| 1634 | + private void verifyPropertyLoaded(CacheVertex v, String propertyName, Boolean isPresent, Method m) { |
| 1635 | + VertexCentricQueryBuilder queryBuilder = v.query().direction(Direction.OUT); |
| 1636 | + //Verify the name property is already present in vertex cache |
| 1637 | + BaseVertexCentricQuery nameQuery = null; |
| 1638 | + try { |
| 1639 | + nameQuery = (BaseVertexCentricQuery) m.invoke(queryBuilder.keys(propertyName), RelationCategory.PROPERTY); |
| 1640 | + } catch (IllegalAccessException | InvocationTargetException e) { |
| 1641 | + throw new RuntimeException(e); |
| 1642 | + } |
| 1643 | + Boolean result = v.hasLoadedRelations(nameQuery.getSubQuery(0).getBackendQuery()); |
| 1644 | + assertEquals(isPresent, result); |
| 1645 | + } |
| 1646 | + |
1448 | 1647 | @Test |
1449 | 1648 | public void testCompositeAndMixedIndexing() { |
1450 | 1649 | final PropertyKey name = makeKey("name", String.class); |
|
0 commit comments