// Copyright 2017 JanusGraph Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package org.janusgraph.graphdb.olap; import com.google.common.base.Preconditions; import com.google.common.collect.HashMultimap; import com.google.common.collect.SetMultimap; import org.janusgraph.core.RelationType; import org.janusgraph.core.JanusGraphTransaction; import org.janusgraph.diskstorage.keycolumnvalue.SliceQuery; import org.janusgraph.graphdb.internal.RelationCategory; import org.janusgraph.graphdb.query.BackendQueryHolder; import org.janusgraph.graphdb.query.JanusGraphPredicate; import org.janusgraph.graphdb.query.vertex.BaseVertexCentricQuery; import org.janusgraph.graphdb.query.vertex.BasicVertexCentricQueryBuilder; import org.janusgraph.graphdb.transaction.StandardJanusGraphTx; import org.apache.tinkerpop.gremlin.process.traversal.Order; import org.apache.tinkerpop.gremlin.structure.Direction; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; /** * @author Matthias Broecheler (me@matthiasb.com) */ public class QueryContainer { public static final int DEFAULT_HARD_QUERY_LIMIT = 100000; public static final String QUERY_NAME_PREFIX = "query$"; private final StandardJanusGraphTx tx; private int hardQueryLimit; private Set<Query> queries; private SetMultimap<SliceQuery, Query> inverseQueries; public QueryContainer(StandardJanusGraphTx tx) { Preconditions.checkArgument(tx != null); this.tx = tx; queries = new HashSet<>(6); inverseQueries = HashMultimap.create(); hardQueryLimit = DEFAULT_HARD_QUERY_LIMIT; } public JanusGraphTransaction getTransaction() { return tx; } public QueryBuilder addQuery() { return new QueryBuilder(); } // Query getQuery(String name) { // return queries.get(name); // } Set<Query> getQueries(SliceQuery slice) { return inverseQueries.get(slice); } Iterable<Query> getQueries() { return queries; } public List<SliceQuery> getSliceQueries() { List<SliceQuery> slices = new ArrayList<>(queries.size() * 2); for (QueryContainer.Query q : getQueries()) { for (SliceQuery slice : q.getSlices()) { if (!slices.contains(slice)) slices.add(slice); } } return slices; } static class Query { private final List<SliceQuery> slices; // private final String name; private final RelationCategory returnType; public Query(List<SliceQuery> slices, RelationCategory returnType) { this.slices = slices; // this.name = name; this.returnType = returnType; } public List<SliceQuery> getSlices() { return slices; } // public String getName() { // return name; // } public RelationCategory getReturnType() { return returnType; } } public class QueryBuilder extends BasicVertexCentricQueryBuilder<QueryBuilder> { // private String name = null; private QueryBuilder() { super(QueryContainer.this.tx); } private Query relations(RelationCategory returnType) { // if (name==null) { // if (hasSingleType()) name = getSingleType().name(); // else if (!requiresName) name = QUERY_NAME_PREFIX + queries.size(); // else throw new IllegalStateException("Need to specify an explicit name for this query"); // } BaseVertexCentricQuery vq = super.constructQuery(returnType); List<SliceQuery> slices = new ArrayList<>(vq.numSubQueries()); for (int i = 0; i < vq.numSubQueries(); i++) { BackendQueryHolder<SliceQuery> bq = vq.getSubQuery(i); SliceQuery sq = bq.getBackendQuery(); slices.add(sq.updateLimit(bq.isFitted() ? vq.getLimit() : hardQueryLimit)); } Query q = new Query(slices, returnType); synchronized (queries) { Preconditions.checkArgument(!queries.contains(q), "Query has already been added: %s", q); queries.add(q); for (SliceQuery sq : slices) { inverseQueries.put(sq, q); } } return q; } @Override protected QueryBuilder getThis() { return this; } // /** // * Sets the name for this query // * @param name // * @return // */ // public QueryBuilder setName(String name) { // Preconditions.checkArgument(StringUtils.isNotBlank(name), "Invalid name provided: %s", name); // this.name=name; // return getThis(); // } public void edges() { relations(RelationCategory.EDGE); } public void relations() { relations(RelationCategory.RELATION); } public void properties() { relations(RelationCategory.PROPERTY); } /* ########### SIMPLE OVERWRITES ########## */ @Override public QueryBuilder has(String type, Object value) { super.has(type, value); return this; } @Override public QueryBuilder hasNot(String key, Object value) { super.hasNot(key, value); return this; } @Override public QueryBuilder has(String key) { super.has(key); return this; } @Override public QueryBuilder hasNot(String key) { super.hasNot(key); return this; } @Override public QueryBuilder has(String key, JanusGraphPredicate predicate, Object value) { super.has(key, predicate, value); return this; } @Override public <T extends Comparable<?>> QueryBuilder interval(String key, T start, T end) { super.interval(key, start, end); return this; } @Override public QueryBuilder types(RelationType... types) { super.types(types); return this; } @Override public QueryBuilder labels(String... labels) { super.labels(labels); return this; } @Override public QueryBuilder keys(String... keys) { super.keys(keys); return this; } public QueryBuilder type(RelationType type) { super.type(type); return this; } @Override public QueryBuilder direction(Direction d) { super.direction(d); return this; } @Override public QueryBuilder limit(int limit) { super.limit(limit); return this; } @Override public QueryBuilder orderBy(String key, Order order) { super.orderBy(key, order); return this; } } }