use of org.janusgraph.graphdb.types.system.ImplicitKey in project janusgraph by JanusGraph.
the class EdgeSerializer method writeRelation.
public StaticArrayEntry writeRelation(InternalRelation relation, InternalRelationType type, int position, TypeInspector tx) {
assert type == relation.getType() || (type.getBaseType() != null && type.getBaseType().equals(relation.getType()));
Direction dir = EdgeDirection.fromPosition(position);
Preconditions.checkArgument(type.isUnidirected(Direction.BOTH) || type.isUnidirected(dir));
long typeId = type.longId();
DirectionID dirID = getDirID(dir, relation.isProperty() ? RelationCategory.PROPERTY : RelationCategory.EDGE);
DataOutput out = serializer.getDataOutput(DEFAULT_CAPACITY);
int valuePosition;
IDHandler.writeRelationType(out, typeId, dirID, type.isInvisibleType());
Multiplicity multiplicity = type.multiplicity();
long[] sortKey = type.getSortKey();
assert !multiplicity.isConstrained() || sortKey.length == 0 : type.name();
int keyStartPos = out.getPosition();
if (!multiplicity.isConstrained()) {
writeInlineTypes(sortKey, relation, out, tx, InlineType.KEY);
}
int keyEndPos = out.getPosition();
long relationId = relation.longId();
// How multiplicity is handled for edges and properties is slightly different
if (relation.isEdge()) {
long otherVertexId = relation.getVertex((position + 1) % 2).longId();
if (multiplicity.isConstrained()) {
if (multiplicity.isUnique(dir)) {
valuePosition = out.getPosition();
VariableLong.writePositive(out, otherVertexId);
} else {
VariableLong.writePositiveBackward(out, otherVertexId);
valuePosition = out.getPosition();
}
VariableLong.writePositive(out, relationId);
} else {
VariableLong.writePositiveBackward(out, otherVertexId);
VariableLong.writePositiveBackward(out, relationId);
valuePosition = out.getPosition();
}
} else {
Preconditions.checkArgument(relation.isProperty(), "Given relation is not property");
Object value = ((JanusGraphVertexProperty) relation).value();
Preconditions.checkNotNull(value);
PropertyKey key = (PropertyKey) type;
assert key.dataType().isInstance(value);
if (multiplicity.isConstrained()) {
if (multiplicity.isUnique(dir)) {
// Cardinality=SINGLE
valuePosition = out.getPosition();
writePropertyValue(out, key, value);
} else {
// Cardinality=SET
writePropertyValue(out, key, value);
valuePosition = out.getPosition();
}
VariableLong.writePositive(out, relationId);
} else {
assert multiplicity.getCardinality() == Cardinality.LIST;
VariableLong.writePositiveBackward(out, relationId);
valuePosition = out.getPosition();
writePropertyValue(out, key, value);
}
}
// Write signature
long[] signature = type.getSignature();
writeInlineTypes(signature, relation, out, tx, InlineType.SIGNATURE);
// Write remaining properties
LongSet writtenTypes = new LongHashSet(sortKey.length + signature.length);
if (sortKey.length > 0 || signature.length > 0) {
for (long id : sortKey) writtenTypes.add(id);
for (long id : signature) writtenTypes.add(id);
}
LongArrayList remainingTypes = new LongArrayList(8);
for (PropertyKey t : relation.getPropertyKeysDirect()) {
if (!(t instanceof ImplicitKey) && !writtenTypes.contains(t.longId())) {
remainingTypes.add(t.longId());
}
}
// Sort types before writing to ensure that value is always written the same way
long[] remaining = remainingTypes.toArray();
Arrays.sort(remaining);
for (long tid : remaining) {
PropertyKey t = tx.getExistingPropertyKey(tid);
writeInline(out, t, relation.getValueDirect(t), InlineType.NORMAL);
}
assert valuePosition > 0;
return new StaticArrayEntry(type.getSortOrder() == Order.DESC ? out.getStaticBufferFlipBytes(keyStartPos, keyEndPos) : out.getStaticBuffer(), valuePosition);
}
use of org.janusgraph.graphdb.types.system.ImplicitKey in project janusgraph by JanusGraph.
the class StandardJanusGraphTx method addProperty.
public JanusGraphVertexProperty addProperty(VertexProperty.Cardinality cardinality, JanusGraphVertex vertex, PropertyKey key, Object value, Long id) {
if (key.cardinality().convert() != cardinality && cardinality != VertexProperty.Cardinality.single)
throw new SchemaViolationException("Key is defined for %s cardinality which conflicts with specified: %s", key.cardinality(), cardinality);
verifyWriteAccess(vertex);
Preconditions.checkArgument(!(key instanceof ImplicitKey), "Cannot create a property of implicit type: %s", key.name());
vertex = ((InternalVertex) vertex).it();
Preconditions.checkNotNull(key);
checkPropertyConstraintForVertexOrCreatePropertyConstraint(vertex, key);
final Object normalizedValue = verifyAttribute(key, value);
Cardinality keyCardinality = key.cardinality();
// Determine unique indexes
final List<IndexLockTuple> uniqueIndexTuples = new ArrayList<>();
for (CompositeIndexType index : TypeUtil.getUniqueIndexes(key)) {
IndexSerializer.IndexRecords matches = IndexSerializer.indexMatches(vertex, index, key, normalizedValue);
for (Object[] match : matches.getRecordValues()) uniqueIndexTuples.add(new IndexLockTuple(index, match));
}
TransactionLock uniqueLock = getUniquenessLock(vertex, (InternalRelationType) key, normalizedValue);
// Add locks for unique indexes
for (IndexLockTuple lockTuple : uniqueIndexTuples) uniqueLock = new CombinerLock(uniqueLock, getLock(lockTuple), times);
uniqueLock.lock(LOCK_TIMEOUT);
try {
// //Check vertex-centric uniqueness -> this doesn't really make sense to check
// if (config.hasVerifyUniqueness()) {
// if (cardinality == Cardinality.SINGLE) {
// if (!Iterables.isEmpty(query(vertex).type(key).properties()))
// throw new SchemaViolationException("A property with the given key [%s] already exists on the vertex [%s] and the property key is defined as single-valued", key.name(), vertex);
// }
// if (cardinality == Cardinality.SET) {
// if (!Iterables.isEmpty(Iterables.filter(query(vertex).type(key).properties(), new Predicate<JanusGraphVertexProperty>() {
// @Override
// public boolean apply(@Nullable JanusGraphVertexProperty janusgraphProperty) {
// return normalizedValue.equals(janusgraphProperty.value());
// }
// })))
// throw new SchemaViolationException("A property with the given key [%s] and value [%s] already exists on the vertex and the property key is defined as set-valued", key.name(), normalizedValue);
// }
// }
long propId = id == null ? IDManager.getTemporaryRelationID(temporaryIds.nextID()) : id;
StandardVertexProperty prop = new StandardVertexProperty(propId, key, (InternalVertex) vertex, normalizedValue, ElementLifeCycle.New);
if (config.hasAssignIDsImmediately() && id == null)
graph.assignID(prop);
// Delete properties if the cardinality is restricted
if (cardinality == VertexProperty.Cardinality.single || cardinality == VertexProperty.Cardinality.set) {
Consumer<JanusGraphVertexProperty> propertyRemover = JanusGraphVertexProperty.getRemover(cardinality, normalizedValue);
if ((!config.hasVerifyUniqueness() || ((InternalRelationType) key).getConsistencyModifier() != ConsistencyModifier.LOCK) && !TypeUtil.hasAnyIndex(key) && cardinality == keyCardinality.convert()) {
// Only delete in-memory so as to not trigger a read from the database which isn't necessary because we will overwrite blindly
// We need to label the new property as "upsert", so that in case property deletion happens, we not only delete this new
// in-memory property, but also read from database to delete the old value (if exists)
((InternalVertex) vertex).getAddedRelations(p -> p.getType().equals(key)).forEach(p -> propertyRemover.accept((JanusGraphVertexProperty) p));
prop.setUpsert(true);
} else {
((InternalVertex) vertex).query().types(key).properties().forEach(propertyRemover);
}
}
// Check index uniqueness
if (config.hasVerifyUniqueness()) {
// Check all unique indexes
for (IndexLockTuple lockTuple : uniqueIndexTuples) {
if (!Iterables.isEmpty(IndexHelper.getQueryResults(lockTuple.getIndex(), lockTuple.getAll(), this)))
throw new SchemaViolationException("Adding this property for key [%s] and value [%s] violates a uniqueness constraint [%s]", key.name(), normalizedValue, lockTuple.getIndex());
}
}
connectRelation(prop);
return prop;
} finally {
uniqueLock.unlock();
}
}
use of org.janusgraph.graphdb.types.system.ImplicitKey in project janusgraph by JanusGraph.
the class EdgeSerializer method parseRelation.
@Override
public RelationCache parseRelation(Entry data, boolean excludeProperties, TypeInspector tx) {
ReadBuffer in = data.asReadBuffer();
RelationTypeParse typeAndDir = IDHandler.readRelationType(in);
long typeId = typeAndDir.typeId;
Direction dir = typeAndDir.dirID.getDirection();
RelationType relationType = tx.getExistingRelationType(typeId);
InternalRelationType def = (InternalRelationType) relationType;
Multiplicity multiplicity = def.multiplicity();
long[] keySignature = def.getSortKey();
long relationId;
Object other;
int startKeyPos = in.getPosition();
int endKeyPos = 0;
if (relationType.isEdgeLabel()) {
long otherVertexId;
if (multiplicity.isConstrained()) {
if (multiplicity.isUnique(dir)) {
otherVertexId = VariableLong.readPositive(in);
} else {
in.movePositionTo(data.getValuePosition());
otherVertexId = VariableLong.readPositiveBackward(in);
in.movePositionTo(data.getValuePosition());
}
relationId = VariableLong.readPositive(in);
} else {
in.movePositionTo(data.getValuePosition());
relationId = VariableLong.readPositiveBackward(in);
otherVertexId = VariableLong.readPositiveBackward(in);
endKeyPos = in.getPosition();
in.movePositionTo(data.getValuePosition());
}
other = otherVertexId;
} else {
assert relationType.isPropertyKey();
PropertyKey key = (PropertyKey) relationType;
if (multiplicity.isConstrained()) {
other = readPropertyValue(in, key);
relationId = VariableLong.readPositive(in);
} else {
in.movePositionTo(data.getValuePosition());
relationId = VariableLong.readPositiveBackward(in);
endKeyPos = in.getPosition();
in.movePositionTo(data.getValuePosition());
other = readPropertyValue(in, key);
}
Preconditions.checkNotNull(other, "Encountered error in deserializer [null value returned]. Check serializer compatibility.");
}
if (!excludeProperties) {
LongObjectHashMap<Object> properties = new LongObjectHashMap<>(4);
if (!multiplicity.isConstrained() && keySignature.length > 0) {
int currentPos = in.getPosition();
// Read sort key which only exists if type is not unique in this direction
assert endKeyPos > startKeyPos;
// after reading the ids, we are on the last byte of the key
int keyLength = endKeyPos - startKeyPos;
in.movePositionTo(startKeyPos);
ReadBuffer inKey = in;
if (def.getSortOrder() == Order.DESC)
inKey = in.subrange(keyLength, true);
readInlineTypes(keySignature, properties, inKey, tx, InlineType.KEY);
in.movePositionTo(currentPos);
}
// read value signature
readInlineTypes(def.getSignature(), properties, in, tx, InlineType.SIGNATURE);
// Third: read rest
while (in.hasRemaining()) {
PropertyKey type = tx.getExistingPropertyKey(IDHandler.readInlineRelationType(in));
Object propertyValue = readInline(in, type, InlineType.NORMAL);
assert propertyValue != null;
properties.put(type.longId(), propertyValue);
}
if (data.hasMetaData()) {
for (Map.Entry<EntryMetaData, Object> metas : data.getMetaData().entrySet()) {
ImplicitKey key = ImplicitKey.MetaData2ImplicitKey.get(metas.getKey());
if (key != null) {
assert metas.getValue() != null;
properties.put(key.longId(), metas.getValue());
}
}
}
return new RelationCache(dir, typeId, relationId, other, properties);
} else {
return new RelationCache(dir, typeId, relationId, other);
}
}
use of org.janusgraph.graphdb.types.system.ImplicitKey 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);
}
Aggregations