All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.thinkaurelius.titan.hadoop.FaunusVertexQuery Maven / Gradle / Ivy

package com.thinkaurelius.titan.hadoop;

import com.carrotsearch.hppc.LongArrayList;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.*;
import com.thinkaurelius.titan.core.*;
import com.thinkaurelius.titan.core.attribute.Cmp;
import com.thinkaurelius.titan.graphdb.internal.ElementLifeCycle;
import com.thinkaurelius.titan.graphdb.internal.RelationCategory;
import com.thinkaurelius.titan.graphdb.query.Query;
import com.thinkaurelius.titan.graphdb.query.condition.*;
import com.thinkaurelius.titan.graphdb.query.vertex.BaseVertexCentricQueryBuilder;
import com.tinkerpop.blueprints.Direction;
import com.tinkerpop.blueprints.Edge;
import com.tinkerpop.blueprints.Vertex;

import javax.annotation.Nullable;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * @author Matthias Broecheler ([email protected])
 */
public class FaunusVertexQuery extends BaseVertexCentricQueryBuilder implements TitanVertexQuery {

    private FaunusPathElement baseElement;

    private static final Logger log =
            LoggerFactory.getLogger(FaunusVertexQuery.class);

    private boolean queryAll;

    public FaunusVertexQuery(FaunusPathElement element) {
        this(element.getTypeManager());
        this.baseElement = element;
    }

    protected FaunusVertexQuery(FaunusSchemaManager typeManager) {
        super(typeManager);
        this.baseElement = null;
    }

    public FaunusVertexQuery queryAll() {
        queryAll=true;
        return getThis();
    }

    @Override
    protected FaunusVertexQuery getThis() {
        return this;
    }

    @Override
    protected TitanVertex getVertex(long vertexid) {
        return new FaunusVertex(baseElement.getFaunusConf(), vertexid);
    }

    /* ################################################
                        EXECUTION
     ################################################*/

    protected And getCondition(FaunusElement element, RelationCategory returnType) {
        FaunusSchemaManager typeManager = element.getTypeManager();
        if (!(element instanceof FaunusVertex)) {
            Preconditions.checkArgument(dir!=Direction.IN,"Illegal direction for element: %s",dir);
            dir = Direction.OUT;
        }
        And conditions = new And(constraints.size()+4);
        if (types.length>0) {
            Or typeConstraints = new Or(types.length);
            for (String type : types) {
                FaunusRelationType rt = typeManager.getRelationType(type);
                if (rt!=null) {
                    typeConstraints.add(new RelationTypeCondition(rt));
                }
            }
            if (typeConstraints.isEmpty()) return null;
            else conditions.add(typeConstraints);
        }
        //Prepare constraints
        for (PredicateCondition constraint : constraints) {
            FaunusRelationType type = typeManager.getRelationType(constraint.getKey());

            if (type == null) {
                if (constraint.getPredicate() == Cmp.EQUAL && constraint.getValue() == null)
                    continue; //Ignore condition, its trivially satisfied
                else return null;
            }
            conditions.add(new PredicateCondition(type,constraint.getPredicate(),constraint.getValue()));
        }
        //Add return type
        conditions.add(returnType);


        //Direction and adjacency condition
        Preconditions.checkArgument(returnType==RelationCategory.EDGE || adjacentVertex==null,
                "Adjacent vertex constraints only applies when querying for edges");
        if (element instanceof FaunusVertex) {
            if (dir!=Direction.BOTH) conditions.add(
                    new DirectionCondition((FaunusVertex)element,dir));
            if (adjacentVertex!=null) conditions.add(
                    new IncidenceCondition((FaunusVertex)element,adjacentVertex));
        } else {
            //Direction constraint == OUT is automatically true for elements
            if (adjacentVertex!=null) conditions.add(
                    new IncidenceDirectionCondition(dir.opposite(),adjacentVertex));
        }

        //System constraints and filters
        if (!queryAll) conditions.add(FILTER_HIDDEN_AND_REMOVED);

        return conditions;
    }

    protected Iterable getRelations(FaunusElement element, RelationCategory returnType) {
        FaunusSchemaManager typeManager = element.getTypeManager();

        final And condition = getCondition(element,returnType);
        if (condition==null) return Collections.EMPTY_LIST;

        Iterable result=null;
        for (Direction direction : Direction.proper) {
            if (dir!=direction && dir!=Direction.BOTH) continue;

            SetMultimap adjacency = element.getAdjacency(direction);
            if (types.length==0) {
                if (result==null) result=adjacency.values();
                else result = Iterables.concat(result,adjacency.values());
            } else {
                for (String type : types) {
                    FaunusRelationType rt = typeManager.getRelationType(type);
                    if (rt==null) continue;
                    Iterable rels;
                    if (rt.isPropertyKey() && ((FaunusPropertyKey)rt).isImplicit()) {
                        FaunusPropertyKey key = (FaunusPropertyKey)rt;
                        Object value = key.computeImplicit(element);
                        if (value!=null)
                            rels = Lists.newArrayList((FaunusRelation)new SimpleFaunusProperty(key,value));
                        else rels = Collections.EMPTY_LIST;
                    } else {
                        rels = adjacency.get(rt);
                    }
                    if (result==null) result=rels;
                    else result = Iterables.concat(result,rels);
                }
            }
        }

        result = new FilterIterable(condition, element, result, dir);

        //Order
        if (!orders.isEmpty()) {
            ArrayList allRels = Lists.newArrayList(result);
            Collections.sort(allRels,orders);
            result = new RemoveOriginalIterable(allRels, element, dir);
        }
        //Limit
        if (limit!= Query.NO_LIMIT) {
            result = Iterables.limit(result,limit);
        }

        return result;
    }

    protected Predicate getFilter(FaunusElement element, RelationCategory returnType) {
        final And condition = getCondition(element,returnType);
        if (condition==null) return Predicates.alwaysFalse();

        if (limit==Query.NO_LIMIT) {
            return new Predicate() {
                @Override
                public boolean apply(@Nullable FaunusRelation faunusRelation) {
                    return condition.evaluate(faunusRelation);
                }
            };
        } else {
            final Set matchingRels = Sets.newHashSet(getRelations(element,returnType));
            return new Predicate() {
                @Override
                public boolean apply(@Nullable FaunusRelation faunusRelation) {
                    return matchingRels.contains(faunusRelation);
                }
            };
        }

    }

    protected Iterable getRelations(RelationCategory returnType) {
        Preconditions.checkState(baseElement!=null,"Query not correctly initialized");
        return getRelations(baseElement,returnType);
    }

    //######### PROXY ############

    @Override
    public Iterable edges() {
        return (Iterable)getRelations(RelationCategory.EDGE);
    }

    @Override
    public Iterable titanEdges() {
        return (Iterable)getRelations(RelationCategory.EDGE);
    }

    @Override
    public Iterable properties() {
        dir = Direction.OUT;
        return (Iterable)getRelations(RelationCategory.PROPERTY);
    }

    @Override
    public Iterable relations() {
        return (Iterable)getRelations(RelationCategory.RELATION);
    }

    @Override
    public Iterable vertices() {
        return Iterables.transform(titanEdges(),new Function() {
            @Nullable
            @Override
            public Vertex apply(@Nullable TitanEdge edge) {
                if (dir!=Direction.BOTH) return edge.getVertex(dir.opposite());
                else {
                    assert (baseElement instanceof FaunusVertex);
                    return edge.getOtherVertex((FaunusVertex)baseElement);
                }
            }
        });
    }

    @Override
    public VertexList vertexIds() {
        FaunusVertexList list = new FaunusVertexList();
        for (Vertex v : vertices()) list.add((FaunusVertex)v);
        return list;
    }

    @Override
    public long count() {
        return Iterables.size(titanEdges());
    }

    @Override
    public long propertyCount() {
        return Iterables.size(properties());
    }

    private static class FaunusVertexList implements VertexList {

        private boolean isSorted = false;
        private final List list = new ArrayList();

        @Override
        public int size() {
            return list.size();
        }

        @Override
        public FaunusVertex get(int pos) {
            return list.get(pos);
        }

        public boolean add(FaunusVertex vertex) {
            isSorted = false;
            return list.add(vertex);
        }

        @Override
        public void sort() {
            Collections.sort(list);
            isSorted = true;
        }

        @Override
        public boolean isSorted() {
            return isSorted;
        }

        @Override
        public VertexList subList(int fromPosition, int length) {
            FaunusVertexList newList = new FaunusVertexList();
            newList.list.addAll(list.subList(fromPosition,fromPosition+length));
            return newList;
        }

        @Override
        public LongArrayList getIDs() {
            LongArrayList arr = new LongArrayList(size());
            for (FaunusVertex v : list) arr.add(v.getLongId());
            return arr;
        }

        @Override
        public long getID(int pos) {
            return get(pos).getLongId();
        }

        @Override
        public Iterator iterator() {
            return (Iterator)list.iterator();
        }
    }

    private static final SystemFilterCondition FILTER_HIDDEN_AND_REMOVED = new SystemFilterCondition();

    private static class SystemFilterCondition extends Literal implements Condition {

        @Override
        public boolean evaluate(TitanRelation relation) {
            FaunusRelation rel = (FaunusRelation)relation;
            return !rel.getType().isHiddenType() && !rel.isRemoved();
        }
    }

    private static class RemoveOriginalIterable implements Iterable {

        private final Iterable original;
        private final FaunusElement element;
        private final Direction dir;

        private RemoveOriginalIterable(Iterable original, FaunusElement element, Direction dir) {
            this.original = original;
            this.element = element;
            this.dir = dir;
        }


        @Override
        public Iterator iterator() {
            return new Iterator() {

                private FaunusRelation current=null;
                private final Iterator iter = original.iterator();

                @Override
                public boolean hasNext() {
                    return iter.hasNext();
                }

                @Override
                public FaunusRelation next() {
                    current = iter.next();
                    return current;
                }

                @Override
                public void remove() {
                    current.updateLifeCycle(ElementLifeCycle.Event.REMOVED);
                    if (current.isNew()) {
                        if (dir.equals(Direction.BOTH) || dir.equals(Direction.IN)) {
                            log.trace("edge removal: edge={} direction={} (in)", current, dir);
                            element.inAdjacency.remove(current.getType(),current);
                        }
                        if (dir.equals(Direction.BOTH) || dir.equals(Direction.OUT)) {
                            log.trace("edge removal: edge={} direction={} (out)", current, dir);
                            element.outAdjacency.remove(current.getType(), current);
                        }
                    }
                    element.updateLifeCycle(ElementLifeCycle.Event.REMOVED_RELATION);
                }
            };
        }
    }

    private static class FilterIterable implements Iterable {

        private final Condition condition;
        private final FaunusElement element;
        private final Iterable original;
        private final Direction dir;

        private FilterIterable(Condition condition, FaunusElement element,
                               Iterable original, Direction dir) {
            this.condition = condition;
            this.element = element;
            this.original = original;
            this.dir = dir;
        }

        @Override
        public Iterator iterator() {
            return new Iterator() {

                private final Iterator iter = original.iterator();
                private FaunusRelation next = null;
                private FaunusRelation current = null;
                private boolean reachedEnd = false;

                @Override
                public boolean hasNext() {
                    while (next==null) {
                        if (!iter.hasNext()) return false;
                        FaunusRelation candidate = iter.next();
                        if (condition.evaluate(candidate)) next = candidate;
                    }
                    if (next==null) reachedEnd=true;
                    return next!=null;
                }

                @Override
                public FaunusRelation next() {
                    if (next==null) {
                        if (!hasNext()) throw new NoSuchElementException();
                    }
                    assert next!=null;
                    current = next;
                    next=null;
                    return current;
                }

                @Override
                public void remove() {
                    if (next==null && !reachedEnd) {
                        current.updateLifeCycle(ElementLifeCycle.Event.REMOVED);
                        //log.trace("Lifecycle removal");
                        if (current.isNew()) {
                            iter.remove();
                            if (dir.equals(Direction.BOTH) || dir.equals(Direction.IN)) {
                                element.inAdjacency.remove(current.getType(),current);
                            }
                            if (dir.equals(Direction.BOTH) || dir.equals(Direction.OUT)) {
                                element.outAdjacency.remove(current.getType(),current);
                            }
                        }
                        element.updateLifeCycle(ElementLifeCycle.Event.REMOVED_RELATION);
                    } else throw new UnsupportedOperationException();
                }
            };
        }
    }


    //######### UNSUPPORTED ############


    @Override
    public QueryDescription describeForEdges() {
        throw new UnsupportedOperationException();
    }

    @Override
    public QueryDescription describeForProperties() {
        throw new UnsupportedOperationException();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy