Skip to content

Commit

Permalink
Lazy load relations and cached query optimization
Browse files Browse the repository at this point in the history
Signed-off-by: ntisseyre <ntisseyre@apple.com>
  • Loading branch information
ntisseyre authored and porunov committed Apr 26, 2024
1 parent 84d4b3b commit eed8756
Show file tree
Hide file tree
Showing 24 changed files with 752 additions and 22 deletions.
3 changes: 3 additions & 0 deletions docs/basics/transactions.md
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,9 @@ following aspects of a transaction to be configured:
cache access during read operations. Doesn't have any effect if database
level cache was disabled via config `cache.db-cache`.

- `lazyLoadRelations()` - Set lazy-load for all properties and edges of the vertex: ids and values are deserialized upon demand.
When enabled, it can have a boost on large-scale read operations, if only certain types of relations are being read from the vertex.

Once, the desired configuration options have been specified, the new
transaction is started via `start()` which returns a
`JanusGraphTransaction`.
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
import org.janusgraph.graphdb.database.util.StaleIndexRecordUtil;
import org.janusgraph.graphdb.internal.ElementCategory;
import org.janusgraph.graphdb.internal.ElementLifeCycle;
import org.janusgraph.graphdb.internal.InternalElement;
import org.janusgraph.graphdb.internal.InternalRelationType;
import org.janusgraph.graphdb.internal.InternalVertex;
import org.janusgraph.graphdb.internal.Order;
Expand All @@ -129,7 +130,6 @@
import org.janusgraph.graphdb.query.condition.PredicateCondition;
import org.janusgraph.graphdb.query.index.IndexSelectionUtil;
import org.janusgraph.graphdb.query.profile.QueryProfiler;
import org.janusgraph.graphdb.relations.AbstractEdge;
import org.janusgraph.graphdb.relations.RelationIdentifier;
import org.janusgraph.graphdb.relations.StandardEdge;
import org.janusgraph.graphdb.relations.StandardVertexProperty;
Expand Down Expand Up @@ -425,7 +425,7 @@ public void testUpdatePropertyPropThenRemoveVertex() {
public void testUpdateEdgePropertyThenRemoveEdge() {
initializeGraphWithVerticesAndEdges();
// normal edge
AbstractEdge edge = (AbstractEdge) graph.traversal().E().has("_e", 1).next();
InternalElement edge = (InternalElement) graph.traversal().E().has("_e", 1).next();
assertTrue(ElementLifeCycle.isLoaded(edge.getLifeCycle()));
Object id = edge.id();

Expand All @@ -452,7 +452,7 @@ public void testUpdateEdgePropertyThenRemoveEdge() {
public void testUpdateForkEdgePropertyThenRemoveEdge() {
initializeGraphWithVerticesAndEdges();
// fork edge
AbstractEdge edge = (AbstractEdge) graph.traversal().E().has("_e", 2).next();
InternalElement edge = (InternalElement) graph.traversal().E().has("_e", 2).next();
assertTrue(ElementLifeCycle.isLoaded(edge.getLifeCycle()));
Object id = edge.id();

Expand Down Expand Up @@ -483,7 +483,7 @@ public void testUpdateForkEdgePropertyThenRemoveEdge() {
@Test
public void testUpdateForkEdgePropertyThenFindEdgeById() {
initializeGraphWithVerticesAndEdges();
AbstractEdge edge = (AbstractEdge) graph.traversal().E().has("_e", 2).next();
InternalElement edge = (InternalElement) graph.traversal().E().has("_e", 2).next();
Object id = edge.id();

edge.property("_e", -2);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright 2024 JanusGraph Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.janusgraph.graphdb.database;

import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration;
import org.janusgraph.graphdb.tinkerpop.optimize.strategy.AdjacentVertexFilterOptimizerStrategy;
import org.janusgraph.graphdb.tinkerpop.optimize.strategy.AdjacentVertexHasIdOptimizerStrategy;
import org.janusgraph.graphdb.tinkerpop.optimize.strategy.AdjacentVertexHasUniquePropertyOptimizerStrategy;
import org.janusgraph.graphdb.tinkerpop.optimize.strategy.AdjacentVertexIsOptimizerStrategy;
import org.janusgraph.graphdb.tinkerpop.optimize.strategy.JanusGraphHasStepStrategy;
import org.janusgraph.graphdb.tinkerpop.optimize.strategy.JanusGraphIoRegistrationStrategy;
import org.janusgraph.graphdb.tinkerpop.optimize.strategy.JanusGraphLocalQueryOptimizerStrategy;
import org.janusgraph.graphdb.tinkerpop.optimize.strategy.JanusGraphMixedIndexAggStrategy;
import org.janusgraph.graphdb.tinkerpop.optimize.strategy.JanusGraphMixedIndexCountStrategy;
import org.janusgraph.graphdb.tinkerpop.optimize.strategy.JanusGraphMultiQueryStrategy;
import org.janusgraph.graphdb.tinkerpop.optimize.strategy.JanusGraphStepStrategy;
import org.janusgraph.graphdb.tinkerpop.optimize.strategy.JanusGraphUnusedMultiQueryRemovalStrategy;
import org.janusgraph.graphdb.transaction.StandardTransactionBuilder;

public class LazyLoadGraphTest extends StandardJanusGraph {

static {
TraversalStrategies graphStrategies =
TraversalStrategies.GlobalCache.getStrategies(Graph.class)
.clone()
.addStrategies(AdjacentVertexFilterOptimizerStrategy.instance(),
AdjacentVertexHasIdOptimizerStrategy.instance(),
AdjacentVertexIsOptimizerStrategy.instance(),
AdjacentVertexHasUniquePropertyOptimizerStrategy.instance(),
JanusGraphLocalQueryOptimizerStrategy.instance(),
JanusGraphHasStepStrategy.instance(),
JanusGraphMultiQueryStrategy.instance(),
JanusGraphUnusedMultiQueryRemovalStrategy.instance(),
JanusGraphMixedIndexAggStrategy.instance(),
JanusGraphMixedIndexCountStrategy.instance(),
JanusGraphStepStrategy.instance(),
JanusGraphIoRegistrationStrategy.instance());

//Register with cache
TraversalStrategies.GlobalCache.registerStrategies(LazyLoadGraphTest.class, graphStrategies);
}

public LazyLoadGraphTest(GraphDatabaseConfiguration configuration) {
super(configuration);
}

@Override
public StandardTransactionBuilder buildTransaction() {
return (StandardTransactionBuilder) new StandardTransactionBuilder(getConfiguration(), this)
.lazyLoadRelations();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright 2024 JanusGraph Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.janusgraph.core;

import org.apache.tinkerpop.gremlin.structure.Direction;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.janusgraph.diskstorage.Entry;
import org.janusgraph.graphdb.internal.InternalRelation;
import org.janusgraph.graphdb.internal.InternalRelationType;
import org.janusgraph.graphdb.internal.InternalVertex;
import org.janusgraph.graphdb.transaction.StandardJanusGraphTx;

public class JanusGraphLazyEdge extends JanusGraphLazyRelation implements JanusGraphEdge {

public JanusGraphLazyEdge(InternalRelation janusGraphRelation,
final InternalVertex vertex,
final StandardJanusGraphTx tx,
final InternalRelationType type) {
super(janusGraphRelation, vertex, tx, type);
}

public JanusGraphLazyEdge(Entry dataEntry,
final InternalVertex vertex,
final StandardJanusGraphTx tx,
final InternalRelationType type) {
super(dataEntry, vertex, tx, type);
}

private JanusGraphEdge loadEdge() {
assert this.isEdge();
return (JanusGraphEdge) this.loadValue();
}

@Override
public JanusGraphVertex vertex(Direction dir) {
return this.loadEdge().vertex(dir);
}

@Override
public JanusGraphVertex otherVertex(Vertex vertex) {
return this.loadEdge().otherVertex(vertex);
}
}
Loading

1 comment on commit eed8756

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark

Benchmark suite Current: eed8756 Previous: c8792aa Ratio
org.janusgraph.JanusGraphSpeedBenchmark.basicAddAndDelete 12678.66442079929 ms/op 12933.219068971923 ms/op 0.98
org.janusgraph.GraphCentricQueryBenchmark.getVertices 916.0243764825278 ms/op 929.0686750649414 ms/op 0.99
org.janusgraph.MgmtOlapJobBenchmark.runClearIndex 216.67149341050722 ms/op 215.98180543333334 ms/op 1.00
org.janusgraph.MgmtOlapJobBenchmark.runReindex 341.4182077570238 ms/op 348.8265452326923 ms/op 0.98
org.janusgraph.JanusGraphSpeedBenchmark.basicCount 249.49973397477777 ms/op 227.8074437066411 ms/op 1.10
org.janusgraph.CQLMultiQueryMultiSlicesBenchmark.getValuesAllPropertiesWithAllMultiQuerySlicesUnderMaxRequestsPerConnection 4704.075343697388 ms/op 4880.398383755226 ms/op 0.96
org.janusgraph.CQLMultiQueryBenchmark.getElementsWithUsingEmitRepeatSteps 17089.148950020644 ms/op 17909.154248616192 ms/op 0.95
org.janusgraph.CQLMultiQueryMultiSlicesBenchmark.getValuesMultiplePropertiesWithSmallBatch 19038.33927982909 ms/op 18799.44054118485 ms/op 1.01
org.janusgraph.CQLMultiQueryMultiSlicesBenchmark.vertexCentricPropertiesFetching 55155.52174623333 ms/op 55455.590322899996 ms/op 0.99
org.janusgraph.CQLMultiQueryBenchmark.getAllElementsTraversedFromOuterVertex 8259.741554868839 ms/op 8339.218499689177 ms/op 0.99
org.janusgraph.CQLMultiQueryBenchmark.getVerticesWithDoubleUnion 378.80942984394284 ms/op 371.31223395833683 ms/op 1.02
org.janusgraph.CQLMultiQueryMultiSlicesBenchmark.getValuesAllPropertiesWithUnlimitedBatch 4097.631038617774 ms/op 4227.4425002369935 ms/op 0.97
org.janusgraph.CQLMultiQueryBenchmark.getNames 8555.594055950249 ms/op 8528.923591561108 ms/op 1.00
org.janusgraph.CQLMultiQueryMultiSlicesBenchmark.getValuesThreePropertiesWithAllMultiQuerySlicesUnderMaxRequestsPerConnection 5567.592398543387 ms/op 5366.416493988495 ms/op 1.04
org.janusgraph.CQLMultiQueryBenchmark.getLabels 7659.8008969863695 ms/op 7119.612218557372 ms/op 1.08
org.janusgraph.CQLMultiQueryBenchmark.getVerticesFilteredByAndStep 427.68424227969876 ms/op 416.6330074327548 ms/op 1.03
org.janusgraph.CQLMultiQueryBenchmark.getVerticesFromMultiNestedRepeatStepStartingFromSingleVertex 13337.651814085833 ms/op 13040.1543998325 ms/op 1.02
org.janusgraph.CQLMultiQueryBenchmark.getVerticesWithCoalesceUsage 361.41930296416683 ms/op 366.6865794040481 ms/op 0.99
org.janusgraph.CQLMultiQueryMultiSlicesBenchmark.getValuesMultiplePropertiesWithAllMultiQuerySlicesUnderMaxRequestsPerConnection 13490.815819325278 ms/op 14169.280107965806 ms/op 0.95
org.janusgraph.CQLMultiQueryBenchmark.getIdToOutVerticesProjection 247.62920066460927 ms/op 243.11426684096145 ms/op 1.02
org.janusgraph.CQLMultiQueryMultiSlicesBenchmark.getValuesMultiplePropertiesWithUnlimitedBatch 14123.495211349142 ms/op 14724.027508337518 ms/op 0.96
org.janusgraph.CQLMultiQueryBenchmark.getNeighborNames 8682.87428737609 ms/op 8379.61509861012 ms/op 1.04
org.janusgraph.CQLMultiQueryBenchmark.getElementsWithUsingRepeatUntilSteps 9231.822722551216 ms/op 9197.912189783667 ms/op 1.00
org.janusgraph.CQLMultiQueryBenchmark.getAdjacentVerticesLocalCounts 9322.620928881099 ms/op 8786.588147997933 ms/op 1.06

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.