Skip to content

Commit

Permalink
Implement index usage to traverse supernodes (pattern matching)
Browse files Browse the repository at this point in the history
  • Loading branch information
luigidellaquila committed Sep 29, 2015
1 parent eece189 commit 4229da9
Show file tree
Hide file tree
Showing 7 changed files with 320 additions and 43 deletions.
@@ -0,0 +1,52 @@
/*
*
* * Copyright 2015 Orient Technologies LTD (info(at)orientdb.com)
* *
* * 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.
* *
* * For more information: http://www.orientdb.com
*
*/

package com.orientechnologies.orient.core.sql.functions;

import com.orientechnologies.orient.core.command.OCommandContext;
import com.orientechnologies.orient.core.db.record.OIdentifiable;

/**
* @author Luigi Dell'Aquila
*/
public interface OSQLFunctionFiltered extends OSQLFunction {

/**
* Process a record.
*
*
* @param iThis
* @param iCurrentRecord
* : current record
* @param iCurrentResult
* TODO
* @param iParams
* : function parameters, number is ensured to be within minParams and maxParams.
* @param iPossibleResults
* : a set of possible results (the function will return, as a result, only items contained in this collection)
* @param iContext
* : object calling this function
* @return function result, can be null. Special cases : can be null if function aggregate results, can be null if function filter
* results : this mean result is excluded
*/
public Object execute(Object iThis, OIdentifiable iCurrentRecord, Object iCurrentResult, Object[] iParams,
Iterable<OIdentifiable> iPossibleResults, OCommandContext iContext);

}
Expand Up @@ -103,7 +103,10 @@ protected Iterable<OIdentifiable> executeTraversal(OMatchStatement.MatchContext

protected Iterable<OIdentifiable> traversePatternEdge(OMatchStatement.MatchContext matchContext, OIdentifiable startingPoint,
OCommandContext iCommandContext) {
Object qR = this.method.execute(startingPoint, iCommandContext);
Iterable possibleResults = matchContext.candidates == null || filter == null ? null : matchContext.candidates.get(filter
.getAlias());

Object qR = this.method.execute(startingPoint, possibleResults, iCommandContext);
return (qR instanceof Iterable) ? (Iterable) qR : Collections.singleton(qR);
}
}
Expand Down
Expand Up @@ -31,7 +31,7 @@ public class OMatchStatement extends OStatement implements OCommandExecutor, OIt

private OSQLAsynchQuery<ODocument> request;

long threshold = 5;
long threshold = 20;

class MatchContext {
int currentEdgeNumber = 0;
Expand Down
Expand Up @@ -8,6 +8,7 @@
import com.orientechnologies.orient.core.db.record.OIdentifiable;
import com.orientechnologies.orient.core.sql.OSQLEngine;
import com.orientechnologies.orient.core.sql.functions.OSQLFunction;
import com.orientechnologies.orient.core.sql.functions.OSQLFunctionFiltered;
import com.orientechnologies.orient.core.sql.method.OSQLMethod;

import java.util.*;
Expand Down Expand Up @@ -46,29 +47,38 @@ public void toString(Map<Object, Object> params, StringBuilder builder) {
if (!first) {
builder.append(", ");
}
param.toString(params,builder);
param.toString(params, builder);
first = false;
}
builder.append(")");
}


public boolean isBidirectional() {
return bidirectionalMethods.contains(methodName.getValue().toLowerCase());
}

public Object execute(Object targetObjects, OCommandContext ctx) {
return execute(targetObjects, ctx, methodName.getValue(), params);
return execute(targetObjects, ctx, methodName.getValue(), params, null);
}

public Object execute(Object targetObjects, Iterable<OIdentifiable> iPossibleResults, OCommandContext ctx) {
return execute(targetObjects, ctx, methodName.getValue(), params, iPossibleResults);
}

private Object execute(Object targetObjects, OCommandContext ctx, String name, List<OExpression> iParams) {
private Object execute(Object targetObjects, OCommandContext ctx, String name, List<OExpression> iParams,
Iterable<OIdentifiable> iPossibleResults) {
List<Object> paramValues = new ArrayList<Object>();
for (OExpression expr : iParams) {
paramValues.add(expr.execute((OIdentifiable) ctx.getVariable("$current"), ctx));
}
if (graphMethods.contains(name)) {
OSQLFunction function = OSQLEngine.getInstance().getFunction(name);
return function.execute(targetObjects, (OIdentifiable) ctx.getVariable("$current"), null, paramValues.toArray(), ctx);
if (function instanceof OSQLFunctionFiltered) {
return ((OSQLFunctionFiltered) function).execute(targetObjects, (OIdentifiable) ctx.getVariable("$current"), null,
paramValues.toArray(), iPossibleResults, ctx);
} else {
return function.execute(targetObjects, (OIdentifiable) ctx.getVariable("$current"), null, paramValues.toArray(), ctx);
}

}
OSQLMethod method = OSQLEngine.getMethod(name);
Expand All @@ -86,14 +96,14 @@ public Object executeReverse(Object targetObjects, OCommandContext ctx) {

String straightName = methodName.getValue();
if (straightName.equalsIgnoreCase("out")) {
return execute(targetObjects, ctx, "in", params);
return execute(targetObjects, ctx, "in", params, null);
}
if (straightName.equalsIgnoreCase("in")) {
return execute(targetObjects, ctx, "out", params);
return execute(targetObjects, ctx, "out", params, null);
}

if (straightName.equalsIgnoreCase("both")) {
return execute(targetObjects, ctx, "both", params);
return execute(targetObjects, ctx, "both", params, null);
}

throw new UnsupportedOperationException("Invalid reverse traversal: " + methodName);
Expand Down
@@ -0,0 +1,83 @@
/*
*
* * Copyright 2015 Orient Technologies LTD (info(at)orientdb.com)
* *
* * 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.
* *
* * For more information: http://www.orientdb.com
*
*/
package com.orientechnologies.orient.graph.sql.functions;

import com.orientechnologies.common.collection.OMultiValue;
import com.orientechnologies.common.io.OIOUtils;
import com.orientechnologies.common.types.OModifiableBoolean;
import com.orientechnologies.common.util.OCallable;
import com.orientechnologies.orient.core.command.OCommandContext;
import com.orientechnologies.orient.core.db.ODatabaseDocumentInternal;
import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal;
import com.orientechnologies.orient.core.db.record.OIdentifiable;
import com.orientechnologies.orient.core.sql.OSQLEngine;
import com.orientechnologies.orient.core.sql.functions.OSQLFunctionFiltered;
import com.orientechnologies.orient.graph.sql.OGraphCommandExecutorSQLFactory;
import com.tinkerpop.blueprints.impls.orient.OrientBaseGraph;

/**
* @author Luigi Dell'Aquila
*/
public abstract class OSQLFunctionMoveFiltered extends OSQLFunctionMove implements OSQLFunctionFiltered{

public OSQLFunctionMoveFiltered() {
super(NAME, 1, 2);
}

public OSQLFunctionMoveFiltered(final String iName, final int iMin, final int iMax) {
super(iName, iMin, iMax);
}


@Override public Object execute(Object iThis, OIdentifiable iCurrentRecord, Object iCurrentResult, Object[] iParameters,
final Iterable<OIdentifiable> iPossibleResults, OCommandContext iContext) {
final OModifiableBoolean shutdownFlag = new OModifiableBoolean();
ODatabaseDocumentInternal curDb = ODatabaseRecordThreadLocal.INSTANCE.get();
final OrientBaseGraph graph = OGraphCommandExecutorSQLFactory.getAnyGraph(shutdownFlag);
try {
final String[] labels;
if (iParameters != null && iParameters.length > 0 && iParameters[0] != null)
labels = OMultiValue.array(iParameters, String.class, new OCallable<Object, Object>() {

@Override
public Object call(final Object iArgument) {
return OIOUtils.getStringContent(iArgument);
}
});
else
labels = null;

return OSQLEngine.foreachRecord(new OCallable<Object, OIdentifiable>() {
@Override
public Object call(final OIdentifiable iArgument) {
return move(graph, iArgument, labels, iPossibleResults);
}
}, iThis, iContext);
} finally {
if (shutdownFlag.getValue())
graph.shutdown(false);
ODatabaseRecordThreadLocal.INSTANCE.set(curDb);
}
}

protected abstract Object move(OrientBaseGraph graph, OIdentifiable iArgument, String[] labels,
Iterable<OIdentifiable> iPossibleResults);

}
@@ -1,36 +1,49 @@
/*
*
* * Copyright 2014 Orient Technologies LTD (info(at)orientechnologies.com)
* *
* * 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.
* *
* * For more information: http://www.orientechnologies.com
*
*/
*
* * Copyright 2014 Orient Technologies LTD (info(at)orientechnologies.com)
* *
* * 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.
* *
* * For more information: http://www.orientechnologies.com
*
*/
package com.orientechnologies.orient.graph.sql.functions;

import com.orientechnologies.common.collection.OMultiCollectionIterator;
import com.orientechnologies.common.util.OSizeable;
import com.orientechnologies.orient.core.db.record.OIdentifiable;
import com.orientechnologies.orient.core.index.OCompositeKey;
import com.orientechnologies.orient.core.index.OIndex;
import com.orientechnologies.orient.core.metadata.schema.OClass;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.tinkerpop.blueprints.Direction;
import com.tinkerpop.blueprints.impls.orient.OrientBaseGraph;
import com.tinkerpop.blueprints.impls.orient.OrientEdge;
import com.tinkerpop.blueprints.impls.orient.OrientVertex;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
* Gets the outgoing Vertices of current Vertex.
*
* @author Luca Garulli (l.garulli--at--orientechnologies.com)
*
*/
public class OSQLFunctionOut extends OSQLFunctionMove {
public static final String NAME = "out";
public class OSQLFunctionOut extends OSQLFunctionMoveFiltered {
public static final String NAME = "out";
int supernodeThreshold = 1000;

public OSQLFunctionOut() {
super(NAME, 0, -1);
Expand All @@ -40,4 +53,66 @@ public OSQLFunctionOut() {
protected Object move(final OrientBaseGraph graph, final OIdentifiable iRecord, final String[] iLabels) {
return v2v(graph, iRecord, Direction.OUT, iLabels);
}

protected Object move(final OrientBaseGraph graph, final OIdentifiable iRecord, final String[] iLabels,
Iterable<OIdentifiable> iPossibleResults) {
if (iPossibleResults == null) {
return v2v(graph, iRecord, Direction.OUT, iLabels);
}

if (!iPossibleResults.iterator().hasNext()) {
return Collections.emptyList();
}

Object edges = v2e(graph, iRecord, Direction.OUT, iLabels);
if (edges instanceof OSizeable) {
int size = ((OSizeable) edges).size();
if (size > supernodeThreshold) {
Object result = fetchFromIndex(graph, iRecord, iPossibleResults, iLabels);
if (result != null) {
return result;
}
}

}

return v2v(graph, iRecord, Direction.OUT, iLabels);
}

private Object fetchFromIndex(OrientBaseGraph graph, OIdentifiable iFrom, Iterable<OIdentifiable> iTo, String[] iEdgeTypes) {
String edgeClassName = null;
if (iEdgeTypes == null) {
edgeClassName = "E";
} else if (iEdgeTypes.length == 1) {
edgeClassName = iEdgeTypes[0];
} else {
return null;
}
OClass edgeClass = graph.getRawGraph().getMetadata().getSchema().getClass(edgeClassName);
if (edgeClass == null) {
return null;
}
Set<OIndex<?>> indexes = edgeClass.getInvolvedIndexes("out", "in");
if (indexes == null || indexes.size() == 0) {
return null;
}
OIndex index = indexes.iterator().next();

OMultiCollectionIterator<OrientVertex> result = new OMultiCollectionIterator<OrientVertex>();
for (OIdentifiable to : iTo) {
OCompositeKey key = new OCompositeKey(iFrom, to);
Object indexResult = index.get(key);
if (indexResult instanceof OIdentifiable) {
indexResult = Collections.singleton(indexResult);
}
Set<OIdentifiable> identities = new HashSet<OIdentifiable>();
for (OIdentifiable edge : ((Iterable<OrientEdge>) indexResult)) {
identities.add((OIdentifiable) ((ODocument) edge.getRecord()).rawField("in"));
}
result.add(identities);
}

return result;
}

}

0 comments on commit 4229da9

Please sign in to comment.