use of org.janusgraph.graphdb.internal.InternalRelationType in project janusgraph by JanusGraph.
the class GraphCentricQueryBuilder method constructQueryWithoutProfile.
public GraphCentricQuery constructQueryWithoutProfile(final ElementCategory resultType) {
Preconditions.checkNotNull(resultType);
if (limit == 0)
return GraphCentricQuery.emptyQuery(resultType);
// Prepare constraints
And<JanusGraphElement> conditions = QueryUtil.constraints2QNF(tx, constraints);
if (conditions == null)
return GraphCentricQuery.emptyQuery(resultType);
// Prepare orders
orders.makeImmutable();
if (orders.isEmpty())
orders = OrderList.NO_ORDER;
// Compile all indexes that cover at least one of the query conditions
final Set<IndexType> indexCandidates = new HashSet<>();
ConditionUtil.traversal(conditions, condition -> {
if (condition instanceof PredicateCondition) {
final RelationType type = ((PredicateCondition<RelationType, JanusGraphElement>) condition).getKey();
Preconditions.checkArgument(type != null && type.isPropertyKey());
Iterables.addAll(indexCandidates, Iterables.filter(((InternalRelationType) type).getKeyIndexes(), indexType -> indexType.getElement() == resultType));
}
return true;
});
/*
Determine the best join index query to answer this query:
Iterate over all potential indexes (as compiled above) and compute a score based on how many clauses
this index covers. The index with the highest score (as long as it covers at least one additional clause)
is picked and added to the joint query for as long as such exist.
*/
JointIndexQuery jointQuery = new JointIndexQuery();
boolean isSorted = orders.isEmpty();
Set<Condition> coveredClauses = Sets.newHashSet();
while (true) {
IndexType bestCandidate = null;
double candidateScore = 0.0;
Set<Condition> candidateSubcover = null;
boolean candidateSupportsSort = false;
Object candidateSubCondition = null;
for (IndexType index : indexCandidates) {
Set<Condition> subcover = Sets.newHashSet();
Object subCondition;
boolean supportsSort = orders.isEmpty();
// Check that this index actually applies in case of a schema constraint
if (index.hasSchemaTypeConstraint()) {
JanusGraphSchemaType type = index.getSchemaTypeConstraint();
Map.Entry<Condition, Collection<Object>> equalCon = getEqualityConditionValues(conditions, ImplicitKey.LABEL);
if (equalCon == null)
continue;
Collection<Object> labels = equalCon.getValue();
assert labels.size() >= 1;
if (labels.size() > 1) {
log.warn("The query optimizer currently does not support multiple label constraints in query: {}", this);
continue;
}
if (!type.name().equals(Iterables.getOnlyElement(labels))) {
continue;
}
subcover.add(equalCon.getKey());
}
if (index.isCompositeIndex()) {
subCondition = indexCover((CompositeIndexType) index, conditions, subcover);
} else {
subCondition = indexCover((MixedIndexType) index, conditions, serializer, subcover);
if (coveredClauses.isEmpty() && !supportsSort && indexCoversOrder((MixedIndexType) index, orders))
supportsSort = true;
}
if (subCondition == null)
continue;
assert !subcover.isEmpty();
double score = 0.0;
boolean coversAdditionalClause = false;
for (Condition c : subcover) {
double s = (c instanceof PredicateCondition && ((PredicateCondition) c).getPredicate() == Cmp.EQUAL) ? EQUAL_CONDITION_SCORE : OTHER_CONDITION_SCORE;
if (coveredClauses.contains(c))
s = s * ALREADY_MATCHED_ADJUSTOR;
else
coversAdditionalClause = true;
score += s;
if (index.isCompositeIndex())
score += ((CompositeIndexType) index).getCardinality() == Cardinality.SINGLE ? CARDINALITY_SINGE_SCORE : CARDINALITY_OTHER_SCORE;
}
if (supportsSort)
score += ORDER_MATCH;
if (coversAdditionalClause && score > candidateScore) {
candidateScore = score;
bestCandidate = index;
candidateSubcover = subcover;
candidateSubCondition = subCondition;
candidateSupportsSort = supportsSort;
}
}
if (bestCandidate != null) {
if (coveredClauses.isEmpty())
isSorted = candidateSupportsSort;
coveredClauses.addAll(candidateSubcover);
if (bestCandidate.isCompositeIndex()) {
jointQuery.add((CompositeIndexType) bestCandidate, serializer.getQuery((CompositeIndexType) bestCandidate, (List<Object[]>) candidateSubCondition));
} else {
jointQuery.add((MixedIndexType) bestCandidate, serializer.getQuery((MixedIndexType) bestCandidate, (Condition) candidateSubCondition, orders));
}
} else {
break;
}
/* TODO: smarter optimization:
- use in-memory histograms to estimate selectivity of PredicateConditions and filter out low-selectivity ones
if they would result in an individual index call (better to filter afterwards in memory)
- move OR's up and extend GraphCentricQuery to allow multiple JointIndexQuery for proper or'ing of queries
*/
}
BackendQueryHolder<JointIndexQuery> query;
if (!coveredClauses.isEmpty()) {
int indexLimit = limit == Query.NO_LIMIT ? HARD_MAX_LIMIT : limit;
if (tx.getGraph().getConfiguration().adjustQueryLimit()) {
indexLimit = limit == Query.NO_LIMIT ? DEFAULT_NO_LIMIT : Math.min(MAX_BASE_LIMIT, limit);
}
indexLimit = Math.min(HARD_MAX_LIMIT, QueryUtil.adjustLimitForTxModifications(tx, coveredClauses.size(), indexLimit));
jointQuery.setLimit(indexLimit);
query = new BackendQueryHolder<>(jointQuery, coveredClauses.size() == conditions.numChildren(), isSorted);
} else {
query = new BackendQueryHolder<>(new JointIndexQuery(), false, isSorted);
}
return new GraphCentricQuery(resultType, conditions, orders, query, limit);
}
use of org.janusgraph.graphdb.internal.InternalRelationType in project janusgraph by JanusGraph.
the class ManagementSystem method changeName.
@Override
public void changeName(JanusGraphSchemaElement element, String newName) {
Preconditions.checkArgument(StringUtils.isNotBlank(newName), "Invalid name: %s", newName);
JanusGraphSchemaVertex schemaVertex = getSchemaVertex(element);
if (schemaVertex.name().equals(newName))
return;
JanusGraphSchemaCategory schemaCategory = schemaVertex.valueOrNull(BaseKey.SchemaCategory);
Preconditions.checkArgument(schemaCategory.hasName(), "Invalid schema element: %s", element);
if (schemaVertex instanceof RelationType) {
InternalRelationType relType = (InternalRelationType) schemaVertex;
if (relType.getBaseType() != null) {
newName = composeRelationTypeIndexName(relType.getBaseType(), newName);
} else
assert !(element instanceof RelationTypeIndex);
JanusGraphSchemaCategory cat = relType.isEdgeLabel() ? JanusGraphSchemaCategory.EDGELABEL : JanusGraphSchemaCategory.PROPERTYKEY;
SystemTypeManager.throwIfSystemName(cat, newName);
} else if (element instanceof VertexLabel) {
SystemTypeManager.throwIfSystemName(JanusGraphSchemaCategory.VERTEXLABEL, newName);
} else if (element instanceof JanusGraphIndex) {
checkIndexName(newName);
}
transaction.addProperty(schemaVertex, BaseKey.SchemaName, schemaCategory.getSchemaName(newName));
updateSchemaVertex(schemaVertex);
schemaVertex.resetCache();
updatedTypes.add(schemaVertex);
}
use of org.janusgraph.graphdb.internal.InternalRelationType in project janusgraph by JanusGraph.
the class ManagementSystem method buildRelationTypeIndex.
private RelationTypeIndex buildRelationTypeIndex(RelationType type, String name, Direction direction, Order sortOrder, PropertyKey... sortKeys) {
Preconditions.checkArgument(type != null && direction != null && sortOrder != null && sortKeys != null);
Preconditions.checkArgument(StringUtils.isNotBlank(name), "Name cannot be blank: %s", name);
Token.verifyName(name);
Preconditions.checkArgument(sortKeys.length > 0, "Need to specify sort keys");
for (RelationType key : sortKeys) Preconditions.checkArgument(key != null, "Keys cannot be null");
Preconditions.checkArgument(!(type instanceof EdgeLabel) || !((EdgeLabel) type).isUnidirected() || direction == Direction.OUT, "Can only index uni-directed labels in the out-direction: %s", type);
Preconditions.checkArgument(!((InternalRelationType) type).multiplicity().isUnique(direction), "The relation type [%s] has a multiplicity or cardinality constraint in direction [%s] and can therefore not be indexed", type, direction);
String composedName = composeRelationTypeIndexName(type, name);
StandardRelationTypeMaker maker;
if (type.isEdgeLabel()) {
StandardEdgeLabelMaker lm = (StandardEdgeLabelMaker) transaction.makeEdgeLabel(composedName);
lm.unidirected(direction);
maker = lm;
} else {
assert type.isPropertyKey();
assert direction == Direction.OUT;
StandardPropertyKeyMaker lm = (StandardPropertyKeyMaker) transaction.makePropertyKey(composedName);
lm.dataType(((PropertyKey) type).dataType());
maker = lm;
}
maker.status(type.isNew() ? SchemaStatus.ENABLED : SchemaStatus.INSTALLED);
maker.invisible();
maker.multiplicity(Multiplicity.MULTI);
maker.sortKey(sortKeys);
maker.sortOrder(sortOrder);
// Compose signature
long[] typeSig = ((InternalRelationType) type).getSignature();
Set<PropertyKey> signature = Sets.newHashSet();
for (long typeId : typeSig) signature.add(transaction.getExistingPropertyKey(typeId));
for (RelationType sortType : sortKeys) signature.remove(sortType);
if (!signature.isEmpty()) {
PropertyKey[] sig = signature.toArray(new PropertyKey[signature.size()]);
maker.signature(sig);
}
RelationType typeIndex = maker.make();
addSchemaEdge(type, typeIndex, TypeDefinitionCategory.RELATIONTYPE_INDEX, null);
RelationTypeIndexWrapper index = new RelationTypeIndexWrapper((InternalRelationType) typeIndex);
if (!type.isNew())
updateIndex(index, SchemaAction.REGISTER_INDEX);
return index;
}
use of org.janusgraph.graphdb.internal.InternalRelationType in project janusgraph by JanusGraph.
the class ModificationDeserializer method parseRelation.
public static InternalRelation parseRelation(TransactionLogHeader.Modification modification, StandardJanusGraphTx tx) {
Change state = modification.state;
assert state.isProper();
long outVertexId = modification.outVertexId;
Entry relEntry = modification.relationEntry;
InternalVertex outVertex = tx.getInternalVertex(outVertexId);
// Special relation parsing, compare to {@link RelationConstructor}
RelationCache relCache = tx.getEdgeSerializer().readRelation(relEntry, false, tx);
assert relCache.direction == Direction.OUT;
InternalRelationType type = (InternalRelationType) tx.getExistingRelationType(relCache.typeId);
assert type.getBaseType() == null;
InternalRelation rel;
if (type.isPropertyKey()) {
if (state == Change.REMOVED) {
rel = new StandardVertexProperty(relCache.relationId, (PropertyKey) type, outVertex, relCache.getValue(), ElementLifeCycle.Removed);
} else {
rel = new CacheVertexProperty(relCache.relationId, (PropertyKey) type, outVertex, relCache.getValue(), relEntry);
}
} else {
assert type.isEdgeLabel();
InternalVertex otherVertex = tx.getInternalVertex(relCache.getOtherVertexId());
if (state == Change.REMOVED) {
rel = new StandardEdge(relCache.relationId, (EdgeLabel) type, outVertex, otherVertex, ElementLifeCycle.Removed);
} else {
rel = new CacheEdge(relCache.relationId, (EdgeLabel) type, outVertex, otherVertex, relEntry);
}
}
if (state == Change.REMOVED && relCache.hasProperties()) {
// copy over properties
for (LongObjectCursor<Object> entry : relCache) {
rel.setPropertyDirect(tx.getExistingPropertyKey(entry.key), entry.value);
}
}
return rel;
}
use of org.janusgraph.graphdb.internal.InternalRelationType in project janusgraph by JanusGraph.
the class IndexRemoveJob method getQueries.
@Override
public List<SliceQuery> getQueries() {
if (isGlobalGraphIndex()) {
// Everything
return ImmutableList.of(new SliceQuery(BufferUtil.zeroBuffer(1), BufferUtil.oneBuffer(128)));
} else {
RelationTypeIndexWrapper wrapper = (RelationTypeIndexWrapper) index;
InternalRelationType wrappedType = wrapper.getWrappedType();
Direction direction = null;
for (Direction dir : Direction.values()) if (wrappedType.isUnidirected(dir))
direction = dir;
assert direction != null;
StandardJanusGraphTx tx = (StandardJanusGraphTx) graph.get().buildTransaction().readOnly().start();
try {
QueryContainer qc = new QueryContainer(tx);
qc.addQuery().type(wrappedType).direction(direction).relations();
return qc.getSliceQueries();
} finally {
tx.rollback();
}
}
}
Aggregations