Search in sources :

Example 6 with SliceQuery

use of org.janusgraph.diskstorage.keycolumnvalue.SliceQuery in project janusgraph by JanusGraph.

the class BasicVertexCentricQueryBuilder method constructSliceQueries.

private void constructSliceQueries(PropertyKey[] extendedSortKey, EdgeSerializer.TypedInterval[] sortKeyConstraints, int position, InternalRelationType bestCandidate, Direction direction, Map<RelationType, Interval> intervalConstraints, int sliceLimit, boolean isIntervalFittedConditions, boolean bestCandidateSupportsOrder, List<BackendQueryHolder<SliceQuery>> queries) {
    if (position < extendedSortKey.length) {
        PropertyKey keyType = extendedSortKey[position];
        Interval interval = intervalConstraints.get(keyType);
        if (interval != null) {
            sortKeyConstraints[position] = new EdgeSerializer.TypedInterval(keyType, interval);
            position++;
        }
        if (interval != null && interval.isPoints()) {
            // Keep invoking recursively to see if we can satisfy more constraints...
            for (Object point : interval.getPoints()) {
                EdgeSerializer.TypedInterval[] clonedSKC = Arrays.copyOf(sortKeyConstraints, sortKeyConstraints.length);
                clonedSKC[position - 1] = new EdgeSerializer.TypedInterval(keyType, new PointInterval(point));
                constructSliceQueries(extendedSortKey, clonedSKC, position, bestCandidate, direction, intervalConstraints, sliceLimit, isIntervalFittedConditions, bestCandidateSupportsOrder, queries);
            }
            return;
        }
    }
    // ...otherwise this is it and we can construct the slicequery
    boolean isFitted = isIntervalFittedConditions && position == intervalConstraints.size();
    if (isFitted && position > 0) {
        // If the last interval is open ended toward the larger values, then its not fitted because we need to
        // filter out NULL values which are serialized with -1 (largest value) byte up front.
        EdgeSerializer.TypedInterval lastInterval = sortKeyConstraints[position - 1];
        if (!lastInterval.interval.isPoints() && lastInterval.interval.getEnd() == null)
            isFitted = false;
    }
    EdgeSerializer serializer = tx.getEdgeSerializer();
    SliceQuery q = serializer.getQuery(bestCandidate, direction, sortKeyConstraints);
    q.setLimit(computeLimit(intervalConstraints.size() - position, sliceLimit));
    queries.add(new BackendQueryHolder<>(q, isFitted, bestCandidateSupportsOrder));
}
Also used : PointInterval(org.janusgraph.util.datastructures.PointInterval) EdgeSerializer(org.janusgraph.graphdb.database.EdgeSerializer) SliceQuery(org.janusgraph.diskstorage.keycolumnvalue.SliceQuery) PointInterval(org.janusgraph.util.datastructures.PointInterval) Interval(org.janusgraph.util.datastructures.Interval) RangeInterval(org.janusgraph.util.datastructures.RangeInterval)

Example 7 with SliceQuery

use of org.janusgraph.diskstorage.keycolumnvalue.SliceQuery in project janusgraph by JanusGraph.

the class EdgeSerializer method getQuery.

public SliceQuery getQuery(InternalRelationType type, Direction dir, TypedInterval[] sortKey) {
    Preconditions.checkNotNull(type);
    Preconditions.checkNotNull(dir);
    Preconditions.checkArgument(type.isUnidirected(Direction.BOTH) || type.isUnidirected(dir));
    StaticBuffer sliceStart = null, sliceEnd = null;
    RelationCategory rt = type.isPropertyKey() ? RelationCategory.PROPERTY : RelationCategory.EDGE;
    if (dir == Direction.BOTH) {
        assert type.isEdgeLabel();
        sliceStart = IDHandler.getRelationType(type.longId(), getDirID(Direction.OUT, rt), type.isInvisibleType());
        sliceEnd = IDHandler.getRelationType(type.longId(), getDirID(Direction.IN, rt), type.isInvisibleType());
        assert sliceStart.compareTo(sliceEnd) < 0;
        sliceEnd = BufferUtil.nextBiggerBuffer(sliceEnd);
    } else {
        DirectionID dirID = getDirID(dir, rt);
        DataOutput colStart = serializer.getDataOutput(DEFAULT_COLUMN_CAPACITY);
        DataOutput colEnd = serializer.getDataOutput(DEFAULT_COLUMN_CAPACITY);
        IDHandler.writeRelationType(colStart, type.longId(), dirID, type.isInvisibleType());
        IDHandler.writeRelationType(colEnd, type.longId(), dirID, type.isInvisibleType());
        long[] sortKeyIDs = type.getSortKey();
        Preconditions.checkArgument(sortKey.length >= sortKeyIDs.length);
        assert colStart.getPosition() == colEnd.getPosition();
        int keyStartPos = colStart.getPosition();
        int keyEndPos = -1;
        for (int i = 0; i < sortKey.length && sortKey[i] != null; i++) {
            PropertyKey propertyKey = sortKey[i].key;
            Interval interval = sortKey[i].interval;
            if (i >= sortKeyIDs.length) {
                assert !type.multiplicity().isUnique(dir);
                assert (propertyKey instanceof ImplicitKey) && (propertyKey == ImplicitKey.JANUSGRAPHID || propertyKey == ImplicitKey.ADJACENT_ID);
                assert propertyKey != ImplicitKey.ADJACENT_ID || (i == sortKeyIDs.length);
                assert propertyKey != ImplicitKey.JANUSGRAPHID || (!type.multiplicity().isConstrained() && (i == sortKeyIDs.length && propertyKey.isPropertyKey() || i == sortKeyIDs.length + 1 && propertyKey.isEdgeLabel()));
                assert colStart.getPosition() == colEnd.getPosition();
                assert interval == null || interval.isPoints();
                keyEndPos = colStart.getPosition();
            } else {
                assert !type.multiplicity().isConstrained();
                assert propertyKey.longId() == sortKeyIDs[i];
            }
            if (interval == null || interval.isEmpty()) {
                break;
            }
            if (interval.isPoints()) {
                if (propertyKey == ImplicitKey.JANUSGRAPHID || propertyKey == ImplicitKey.ADJACENT_ID) {
                    assert !type.multiplicity().isUnique(dir);
                    VariableLong.writePositiveBackward(colStart, (Long) interval.getStart());
                    VariableLong.writePositiveBackward(colEnd, (Long) interval.getEnd());
                } else {
                    writeInline(colStart, propertyKey, interval.getStart(), InlineType.KEY);
                    writeInline(colEnd, propertyKey, interval.getEnd(), InlineType.KEY);
                }
            } else {
                if (interval.getStart() != null)
                    writeInline(colStart, propertyKey, interval.getStart(), InlineType.KEY);
                if (interval.getEnd() != null)
                    writeInline(colEnd, propertyKey, interval.getEnd(), InlineType.KEY);
                switch(type.getSortOrder()) {
                    case ASC:
                        sliceStart = colStart.getStaticBuffer();
                        sliceEnd = colEnd.getStaticBuffer();
                        if (!interval.startInclusive())
                            sliceStart = BufferUtil.nextBiggerBuffer(sliceStart);
                        if (interval.endInclusive())
                            sliceEnd = BufferUtil.nextBiggerBuffer(sliceEnd);
                        break;
                    case DESC:
                        sliceEnd = colStart.getStaticBufferFlipBytes(keyStartPos, colStart.getPosition());
                        sliceStart = colEnd.getStaticBufferFlipBytes(keyStartPos, colEnd.getPosition());
                        if (interval.startInclusive())
                            sliceEnd = BufferUtil.nextBiggerBuffer(sliceEnd);
                        if (!interval.endInclusive())
                            sliceStart = BufferUtil.nextBiggerBuffer(sliceStart);
                        break;
                    default:
                        throw new AssertionError(type.getSortOrder().toString());
                }
                assert sliceStart.compareTo(sliceEnd) <= 0;
                break;
            }
        }
        if (sliceStart == null) {
            assert sliceEnd == null && colStart.getPosition() == colEnd.getPosition();
            if (keyEndPos < 0)
                keyEndPos = colStart.getPosition();
            switch(type.getSortOrder()) {
                case ASC:
                    sliceStart = colStart.getStaticBuffer();
                    break;
                case DESC:
                    sliceStart = colStart.getStaticBufferFlipBytes(keyStartPos, keyEndPos);
                    break;
                default:
                    throw new AssertionError(type.getSortOrder().toString());
            }
            sliceEnd = BufferUtil.nextBiggerBuffer(sliceStart);
        }
    }
    return new SliceQuery(sliceStart, sliceEnd);
}
Also used : DataOutput(org.janusgraph.graphdb.database.serialize.DataOutput) StaticBuffer(org.janusgraph.diskstorage.StaticBuffer) ImplicitKey(org.janusgraph.graphdb.types.system.ImplicitKey) SliceQuery(org.janusgraph.diskstorage.keycolumnvalue.SliceQuery) DirectionID(org.janusgraph.graphdb.database.idhandling.IDHandler.DirectionID) Interval(org.janusgraph.util.datastructures.Interval)

Example 8 with SliceQuery

use of org.janusgraph.diskstorage.keycolumnvalue.SliceQuery 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();
        }
    }
}
Also used : StandardJanusGraphTx(org.janusgraph.graphdb.transaction.StandardJanusGraphTx) RelationTypeIndexWrapper(org.janusgraph.graphdb.database.management.RelationTypeIndexWrapper) InternalRelationType(org.janusgraph.graphdb.internal.InternalRelationType) Direction(org.apache.tinkerpop.gremlin.structure.Direction) SliceQuery(org.janusgraph.diskstorage.keycolumnvalue.SliceQuery) QueryContainer(org.janusgraph.graphdb.olap.QueryContainer)

Example 9 with SliceQuery

use of org.janusgraph.diskstorage.keycolumnvalue.SliceQuery 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), ((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: " + type.name());
                returnType = RelationCategory.PROPERTY;
                typeDir = Direction.OUT;
            }
            if (type.isEdgeLabel()) {
                Preconditions.checkArgument(returnType != RelationCategory.PROPERTY, "Querying for properties but including an edge label: " + 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;
                    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();
                        }
                    }
                    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
                    PropertyKey[] extendedSortKey = getExtendedSortKey(bestCandidate, direction, tx);
                    EdgeSerializer.TypedInterval[] sortKeyConstraints = new EdgeSerializer.TypedInterval[extendedSortKey.length];
                    constructSliceQueries(extendedSortKey, sortKeyConstraints, 0, bestCandidate, direction, intervalConstraints, sliceLimit, isIntervalFittedConditions, bestCandidateSupportsOrder, queries);
                }
            }
        }
        if (queries.isEmpty())
            return BaseVertexCentricQuery.emptyQuery();
        conditions.add(getTypeCondition(ts));
    }
    return new BaseVertexCentricQuery(QueryUtil.simplifyQNF(conditions), dir, queries, orders, limit);
}
Also used : Direction(org.apache.tinkerpop.gremlin.structure.Direction) SystemRelationType(org.janusgraph.graphdb.types.system.SystemRelationType) EdgeSerializer(org.janusgraph.graphdb.database.EdgeSerializer) ImplicitKey(org.janusgraph.graphdb.types.system.ImplicitKey) SliceQuery(org.janusgraph.diskstorage.keycolumnvalue.SliceQuery) SystemRelationType(org.janusgraph.graphdb.types.system.SystemRelationType) PointInterval(org.janusgraph.util.datastructures.PointInterval) Interval(org.janusgraph.util.datastructures.Interval) RangeInterval(org.janusgraph.util.datastructures.RangeInterval)

Example 10 with SliceQuery

use of org.janusgraph.diskstorage.keycolumnvalue.SliceQuery in project janusgraph by JanusGraph.

the class CacheVertex method loadRelations.

@Override
public EntryList loadRelations(final SliceQuery query, final Retriever<SliceQuery, EntryList> lookup) {
    if (isNew())
        return EntryList.EMPTY_LIST;
    EntryList result;
    synchronized (queryCache) {
        result = queryCache.get(query);
    }
    if (result == null) {
        // First check for super
        Map.Entry<SliceQuery, EntryList> superset = getSuperResultSet(query);
        if (superset == null) {
            result = lookup.get(query);
        } else {
            result = query.getSubset(superset.getKey(), superset.getValue());
        }
        addToQueryCache(query, result);
    }
    return result;
}
Also used : EntryList(org.janusgraph.diskstorage.EntryList) Map(java.util.Map) HashMap(java.util.HashMap) SliceQuery(org.janusgraph.diskstorage.keycolumnvalue.SliceQuery)

Aggregations

SliceQuery (org.janusgraph.diskstorage.keycolumnvalue.SliceQuery)15 StaticBuffer (org.janusgraph.diskstorage.StaticBuffer)4 EntryList (org.janusgraph.diskstorage.EntryList)3 Interval (org.janusgraph.util.datastructures.Interval)3 Instant (java.time.Instant)2 ArrayList (java.util.ArrayList)2 Map (java.util.Map)2 Direction (org.apache.tinkerpop.gremlin.structure.Direction)2 KeySliceQuery (org.janusgraph.diskstorage.keycolumnvalue.KeySliceQuery)2 CacheTransaction (org.janusgraph.diskstorage.keycolumnvalue.cache.CacheTransaction)2 EdgeSerializer (org.janusgraph.graphdb.database.EdgeSerializer)2 ImplicitKey (org.janusgraph.graphdb.types.system.ImplicitKey)2 PointInterval (org.janusgraph.util.datastructures.PointInterval)2 RangeInterval (org.janusgraph.util.datastructures.RangeInterval)2 IOException (java.io.IOException)1 HashMap (java.util.HashMap)1 ExecutionException (java.util.concurrent.ExecutionException)1 BaseConfiguration (org.apache.commons.configuration.BaseConfiguration)1 JanusGraphVertex (org.janusgraph.core.JanusGraphVertex)1 CommonsConfiguration (org.janusgraph.diskstorage.configuration.backend.CommonsConfiguration)1