use of org.janusgraph.core.RelationType in project janusgraph by JanusGraph.
the class MapReduceIndexManagement method updateIndex.
/**
* Updates the provided index according to the given {@link SchemaAction}.
* Only {@link SchemaAction#REINDEX} and {@link SchemaAction#REMOVE_INDEX} are supported.
*
* @param index the index to process
* @param updateAction either {@code REINDEX} or {@code REMOVE_INDEX}
* @param hadoopConf
* @return a future that returns immediately;
* this method blocks until the Hadoop MapReduce job completes
*/
// TODO make this future actually async and update javadoc @return accordingly
public ScanJobFuture updateIndex(Index index, SchemaAction updateAction, Configuration hadoopConf) throws BackendException {
Preconditions.checkNotNull(index, "Index parameter must not be null", index);
Preconditions.checkNotNull(updateAction, "%s parameter must not be null", SchemaAction.class.getSimpleName());
Preconditions.checkArgument(SUPPORTED_ACTIONS.contains(updateAction), "Only these %s parameters are supported: %s (was given %s)", SchemaAction.class.getSimpleName(), SUPPORTED_ACTIONS_STRING, updateAction);
Preconditions.checkArgument(RelationTypeIndex.class.isAssignableFrom(index.getClass()) || JanusGraphIndex.class.isAssignableFrom(index.getClass()), "Index %s has class %s: must be a %s or %s (or subtype)", index.getClass(), RelationTypeIndex.class.getSimpleName(), JanusGraphIndex.class.getSimpleName());
ModifiableHadoopConfiguration janusGraphMapReduceConfiguration = ModifiableHadoopConfiguration.of(JanusGraphHadoopConfiguration.MAPRED_NS, hadoopConf);
// The job we'll execute to either REINDEX or REMOVE_INDEX
final Class<? extends IndexUpdateJob> indexJobClass;
final Class<? extends Mapper> mapperClass;
// The class of the IndexUpdateJob and the Mapper that will be used to run it (VertexScanJob vs ScanJob)
if (updateAction.equals(SchemaAction.REINDEX)) {
indexJobClass = IndexRepairJob.class;
mapperClass = HadoopVertexScanMapper.class;
} else {
assert updateAction.equals(SchemaAction.REMOVE_INDEX);
indexJobClass = IndexRemoveJob.class;
mapperClass = HadoopScanMapper.class;
}
// The column family that serves as input to the IndexUpdateJob
final String readCF;
if (RelationTypeIndex.class.isAssignableFrom(index.getClass())) {
readCF = Backend.EDGESTORE_NAME;
} else {
JanusGraphIndex graphIndex = (JanusGraphIndex) index;
if (graphIndex.isMixedIndex() && !updateAction.equals(SchemaAction.REINDEX))
throw new UnsupportedOperationException("External mixed indexes must be removed in the indexing system directly.");
Preconditions.checkState(JanusGraphIndex.class.isAssignableFrom(index.getClass()));
if (updateAction.equals(SchemaAction.REMOVE_INDEX))
readCF = Backend.INDEXSTORE_NAME;
else
readCF = Backend.EDGESTORE_NAME;
}
janusGraphMapReduceConfiguration.set(JanusGraphHadoopConfiguration.COLUMN_FAMILY_NAME, readCF);
// The MapReduce InputFormat class based on the open graph's store manager
HadoopStoreManager storeManager = (HadoopStoreManager) graph.getBackend().getStoreManager().getHadoopManager();
if (storeManager == null) {
throw new IllegalArgumentException("Store manager class " + graph.getBackend().getStoreManagerClass() + "is not supported");
}
final Class<? extends InputFormat> inputFormat = storeManager.getInputFormat(hadoopConf);
// The index name and relation type name (if the latter is applicable)
final String indexName = index.name();
final RelationType relationType = RelationTypeIndex.class.isAssignableFrom(index.getClass()) ? ((RelationTypeIndex) index).getType() : null;
final String relationTypeName = relationType == null ? StringUtils.EMPTY : relationType.name();
Preconditions.checkNotNull(indexName);
// Set the class of the IndexUpdateJob
janusGraphMapReduceConfiguration.set(JanusGraphHadoopConfiguration.SCAN_JOB_CLASS, indexJobClass.getName());
// Set the configuration of the IndexUpdateJob
copyIndexJobKeys(hadoopConf, indexName, relationTypeName);
janusGraphMapReduceConfiguration.set(JanusGraphHadoopConfiguration.SCAN_JOB_CONFIG_ROOT, GraphDatabaseConfiguration.class.getName() + "#JOB_NS");
// Copy the StandardJanusGraph configuration under JanusGraphHadoopConfiguration.GRAPH_CONFIG_KEYS
org.apache.commons.configuration2.Configuration localConfiguration = graph.getConfiguration().getConfigurationAtOpen();
localConfiguration.clearProperty(Graph.GRAPH);
copyInputKeys(hadoopConf, localConfiguration);
String jobName = HadoopScanMapper.class.getSimpleName() + "[" + indexJobClass.getSimpleName() + "]";
try {
return new CompletedJobFuture(HadoopScanRunner.runJob(hadoopConf, inputFormat, jobName, mapperClass));
} catch (Exception e) {
return new FailedJobFuture(e);
}
}
use of org.janusgraph.core.RelationType in project janusgraph by JanusGraph.
the class BasicVertexCentricQueryBuilder method constructQueryWithoutProfile.
protected BaseVertexCentricQuery constructQueryWithoutProfile(RelationCategory returnType) {
assert returnType != null;
Preconditions.checkArgument(adjacentVertex == null || returnType == RelationCategory.EDGE, "Vertex constraints only apply to edges");
if (limit <= 0)
return BaseVertexCentricQuery.emptyQuery();
// Prepare direction
if (returnType == RelationCategory.PROPERTY) {
if (dir == Direction.IN)
return BaseVertexCentricQuery.emptyQuery();
dir = Direction.OUT;
}
// Prepare order
orders.makeImmutable();
assert orders.hasCommonOrder();
// Prepare constraints
And<JanusGraphRelation> conditions = QueryUtil.constraints2QNF(tx, constraints);
if (conditions == null)
return BaseVertexCentricQuery.emptyQuery();
// Don't be smart with query limit adjustments - it just messes up the caching layer and
// penalizes when appropriate limits are set by the user!
int sliceLimit = limit;
// Construct (optimal) SliceQueries
EdgeSerializer serializer = tx.getEdgeSerializer();
List<BackendQueryHolder<SliceQuery>> queries;
if (!hasTypes()) {
final BackendQueryHolder<SliceQuery> query = new BackendQueryHolder<>(serializer.getQuery(returnType, querySystem), (adjacentVertex == null && dir == Direction.BOTH || returnType == RelationCategory.PROPERTY && dir == Direction.OUT) && !conditions.hasChildren(), orders.isEmpty());
if (sliceLimit != Query.NO_LIMIT && sliceLimit < Integer.MAX_VALUE / 3) {
// half will be filtered
if (dir != Direction.BOTH && (returnType == RelationCategory.EDGE || returnType == RelationCategory.RELATION)) {
sliceLimit *= 2;
}
}
query.getBackendQuery().setLimit(computeLimit(conditions.size(), sliceLimit));
queries = ImmutableList.of(query);
conditions.add(returnType);
conditions.add(new VisibilityFilterCondition<>(// Need this to filter out newly created invisible relations in the transaction
querySystem ? VisibilityFilterCondition.Visibility.SYSTEM : VisibilityFilterCondition.Visibility.NORMAL));
} else {
final Set<RelationType> ts = new HashSet<>(types.length);
queries = new ArrayList<>(types.length + 2);
final Map<RelationType, Interval> intervalConstraints = new HashMap<>(conditions.size());
final boolean isIntervalFittedConditions = compileConstraints(conditions, intervalConstraints);
for (Interval pint : intervalConstraints.values()) {
// Check if one of the constraints leads to an empty result set
if (pint.isEmpty())
return BaseVertexCentricQuery.emptyQuery();
}
for (String typeName : types) {
InternalRelationType type = QueryUtil.getType(tx, typeName);
if (type == null)
continue;
Preconditions.checkArgument(!querySystem || (type instanceof SystemRelationType), "Can only query for system types: %s", type);
if (type instanceof ImplicitKey) {
throw new UnsupportedOperationException("Implicit types are not supported in complex queries: " + type);
}
ts.add(type);
Direction typeDir = dir;
if (type.isPropertyKey()) {
Preconditions.checkArgument(returnType != RelationCategory.EDGE, "Querying for edges but including a property key: %s", type.name());
returnType = RelationCategory.PROPERTY;
typeDir = Direction.OUT;
}
if (type.isEdgeLabel()) {
Preconditions.checkArgument(returnType != RelationCategory.PROPERTY, "Querying for properties but including an edge label: %s", type.name());
returnType = RelationCategory.EDGE;
if (!type.isUnidirected(Direction.BOTH)) {
// Make sure unidirectionality lines up
if (typeDir == Direction.BOTH) {
if (type.isUnidirected(Direction.OUT))
typeDir = Direction.OUT;
else
typeDir = Direction.IN;
} else // Directions are incompatible
if (!type.isUnidirected(typeDir))
continue;
}
}
if (type.isEdgeLabel() && typeDir == Direction.BOTH && intervalConstraints.isEmpty() && orders.isEmpty()) {
// TODO: This if-condition is a little too restrictive - we also want to include those cases where
// there ARE intervalConstraints or orders but those cannot be covered by any sort-keys
SliceQuery q = serializer.getQuery(type, typeDir, null);
q.setLimit(sliceLimit);
queries.add(new BackendQueryHolder<>(q, isIntervalFittedConditions, true));
} else {
// Optimize for each direction independently
Direction[] dirs = { typeDir };
if (typeDir == Direction.BOTH) {
if (type.isEdgeLabel())
dirs = new Direction[] { Direction.OUT, Direction.IN };
else
// property key
dirs = new Direction[] { Direction.OUT };
}
for (Direction direction : dirs) {
/*
Find best scoring relation type to answer this query with. We score each candidate by the number
of conditions that each sort-keys satisfy. Equality conditions score higher than interval
conditions since they are more restrictive. We assign additional points if the sort key
satisfies the order of this query.
*/
InternalRelationType bestCandidate = null;
double bestScore = Double.NEGATIVE_INFINITY;
boolean bestCandidateSupportsOrder = false;
PropertyKey[] bestCandidateExtendedSortKey = null;
for (InternalRelationType candidate : type.getRelationIndexes()) {
// Filter out those that don't apply
if (!candidate.isUnidirected(Direction.BOTH) && !candidate.isUnidirected(direction)) {
continue;
}
if (!candidate.equals(type) && candidate.getStatus() != SchemaStatus.ENABLED)
continue;
boolean supportsOrder = orders.isEmpty() || orders.getCommonOrder() == candidate.getSortOrder();
int currentOrder = 0;
double score = 0.0;
PropertyKey[] extendedSortKey = getExtendedSortKey(candidate, direction, tx);
for (PropertyKey keyType : extendedSortKey) {
if (currentOrder < orders.size() && orders.getKey(currentOrder).equals(keyType))
currentOrder++;
Interval interval = intervalConstraints.get(keyType);
if (interval == null || !interval.isPoints()) {
if (interval != null)
score += 1;
break;
} else {
assert interval.isPoints();
score += 5.0 / interval.getPoints().size();
}
}
if (supportsOrder && currentOrder == orders.size())
score += 3;
if (score > bestScore) {
bestScore = score;
bestCandidate = candidate;
bestCandidateSupportsOrder = supportsOrder && currentOrder == orders.size();
bestCandidateExtendedSortKey = extendedSortKey;
}
}
Preconditions.checkArgument(bestCandidate != null, "Current graph schema does not support the specified query constraints for type: %s", type.name());
// Construct sort key constraints for the best candidate and then serialize into a SliceQuery
// that is wrapped into a BackendQueryHolder
EdgeSerializer.TypedInterval[] sortKeyConstraints = new EdgeSerializer.TypedInterval[bestCandidateExtendedSortKey.length];
constructSliceQueries(bestCandidateExtendedSortKey, sortKeyConstraints, 0, bestCandidate, direction, intervalConstraints, sliceLimit, isIntervalFittedConditions, bestCandidateSupportsOrder, queries);
}
}
}
if (queries.isEmpty())
return BaseVertexCentricQuery.emptyQuery();
conditions.add(getTypeCondition(ts));
}
return new BaseVertexCentricQuery(QueryUtil.simplifyAnd(conditions), dir, queries, orders, limit);
}
use of org.janusgraph.core.RelationType in project janusgraph by JanusGraph.
the class AbstractIndexSelectionStrategy method coversAll.
private boolean coversAll(final MixedIndexType index, Condition<JanusGraphElement> condition, IndexSerializer indexInfo) {
if (condition.getType() != Condition.Type.LITERAL) {
return StreamSupport.stream(condition.getChildren().spliterator(), false).allMatch(child -> coversAll(index, child, indexInfo));
}
if (!(condition instanceof PredicateCondition)) {
return false;
}
final PredicateCondition<RelationType, JanusGraphElement> atom = (PredicateCondition) condition;
if (atom.getValue() == null && atom.getPredicate() != Cmp.NOT_EQUAL) {
return false;
}
Preconditions.checkArgument(atom.getKey().isPropertyKey());
final PropertyKey key = (PropertyKey) atom.getKey();
final ParameterIndexField[] fields = index.getFieldKeys();
final ParameterIndexField match = Arrays.stream(fields).filter(field -> field.getStatus() == SchemaStatus.ENABLED).filter(field -> field.getFieldKey().equals(key)).findAny().orElse(null);
if (match == null) {
return false;
}
boolean existsQuery = atom.getValue() == null && atom.getPredicate() == Cmp.NOT_EQUAL && indexInfo.supportsExistsQuery(index, match);
return existsQuery || indexInfo.supports(index, match, atom.getPredicate());
}
use of org.janusgraph.core.RelationType in project janusgraph by JanusGraph.
the class IndexRepairJob method addIndexSchemaConstraint.
private static <Q extends BaseVertexQuery> Q addIndexSchemaConstraint(Q query, IndexType indexType) {
if (indexType.hasSchemaTypeConstraint()) {
JanusGraphSchemaType constraint = indexType.getSchemaTypeConstraint();
Preconditions.checkArgument(constraint instanceof RelationType, "Expected constraint to be a " + "relation type: %s", constraint);
query.types((RelationType) constraint);
}
return query;
}
use of org.janusgraph.core.RelationType in project janusgraph by JanusGraph.
the class RelationIdentifierUtils method findRelation.
protected static JanusGraphRelation findRelation(RelationIdentifier rId, JanusGraphTransaction tx) {
JanusGraphVertex v = ((StandardJanusGraphTx) tx).getInternalVertex(rId.getOutVertexId());
if (v == null || v.isRemoved())
return null;
JanusGraphVertex typeVertex = tx.getVertex(rId.getTypeId());
if (typeVertex == null)
return null;
if (!(typeVertex instanceof RelationType))
throw new IllegalArgumentException("Invalid RelationIdentifier: typeID does not reference a type");
Iterable<? extends JanusGraphRelation> relations = getJanusGraphRelations(rId, tx, v, (RelationType) typeVertex);
for (JanusGraphRelation r : relations) {
// Find current or previous relation
if (r.longId() == rId.getRelationId() || ((r instanceof StandardRelation) && ((StandardRelation) r).getPreviousID() == rId.getRelationId()))
return r;
}
return null;
}
Aggregations