Java tutorial
/* * Grakn - A Distributed Semantic Database * Copyright (C) 2016 Grakn Labs Limited * * Grakn is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Grakn is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Grakn. If not, see <http://www.gnu.org/licenses/gpl.txt>. */ package ai.grakn.graql.internal.reasoner; import ai.grakn.GraknGraph; import ai.grakn.graql.Var; import ai.grakn.graql.admin.Atomic; import ai.grakn.graql.admin.VarProperty; import ai.grakn.graql.internal.gremlin.GraqlTraversal; import ai.grakn.graql.internal.gremlin.GreedyTraversalPlan; import ai.grakn.graql.internal.gremlin.fragment.Fragment; import ai.grakn.graql.internal.reasoner.atom.Atom; import ai.grakn.graql.internal.reasoner.atom.predicate.IdPredicate; import ai.grakn.graql.internal.reasoner.query.ReasonerQueries; import ai.grakn.graql.internal.reasoner.query.ReasonerQueryImpl; import com.google.common.collect.ImmutableList; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; /** * * <p> * Class defining the resolution plan in terms of different weights applicable to certain {@link Atom} configurations. * </p> * * @author Kasper Piskorski * */ public final class ResolutionPlan { /** * priority modifier for each partial substitution a given atom has */ public static final int PARTIAL_SUBSTITUTION = 30; /** * priority modifier if a given atom is a resource atom */ public static final int IS_RESOURCE_ATOM = 0; /** * priority modifier if a given atom is a resource atom attached to a relation */ public static final int RESOURCE_REIFYING_RELATION = 20; /** * priority modifier if a given atom is a type atom */ public static final int IS_TYPE_ATOM = 0; /** * priority modifier if a given atom is a relation atom */ public static final int IS_RELATION_ATOM = 2; /** * priority modifier if a given atom is a type atom without specific type * NB: atom satisfying this criterion should be resolved last */ public static final int NON_SPECIFIC_TYPE_ATOM = -1000; public static final int RULE_RESOLVABLE_ATOM = -10; /** * priority modifier if a given atom is recursive atom */ public static final int RECURSIVE_ATOM = -5; /** * priority modifier for guard (type atom) the atom has */ public static final int GUARD = 1; /** * priority modifier for guard (type atom) the atom has - favour boundary rather than bulk atoms */ public static final int BOUND_VARIABLE = -2; /** * priority modifier if an atom has an inequality predicate */ public static final int INEQUALITY_PREDICATE = -1000; /** * priority modifier for each specific value predicate a given atom (resource) has */ public static final int SPECIFIC_VALUE_PREDICATE = 20; /** * priority modifier for each non-specific value predicate a given atom (resource) has */ public static final int NON_SPECIFIC_VALUE_PREDICATE = 5; /** * priority modifier for each value predicate with variable */ public static final int VARIABLE_VALUE_PREDICATE = -100; /** * number of entities that need to be attached to a resource wtih a specific value to be considered a supernode */ public static final int RESOURCE_SUPERNODE_SIZE = 5; /** * priority modifier for each value predicate with variable requiring comparison * NB: atom satisfying this criterion should be resolved last */ public static final int COMPARISON_VARIABLE_VALUE_PREDICATE = -1000; /** * compute the resolution plan - list of atomic queries ordered by their cost as computed by the graql traversal planner * @return list of prioritised queries */ public static LinkedList<ReasonerQueryImpl> getResolutionPlanFromTraversal(ReasonerQueryImpl query) { LinkedList<ReasonerQueryImpl> queries = new LinkedList<>(); GraknGraph graph = query.graph(); Map<VarProperty, Atom> propertyMap = new HashMap<>(); query.getAtoms().stream().filter(Atomic::isSelectable).map(at -> (Atom) at) .forEach(at -> at.getVarProperties().forEach(p -> propertyMap.put(p, at))); Set<VarProperty> properties = propertyMap.keySet(); GraqlTraversal graqlTraversal = GreedyTraversalPlan.createTraversal(query.getPattern(), graph); ImmutableList<Fragment> fragments = graqlTraversal.fragments().iterator().next(); LinkedList<Atom> atoms = fragments.stream().map(Fragment::getVarProperty).filter(Objects::nonNull) .filter(properties::contains).distinct().map(propertyMap::get).distinct() .collect(Collectors.toCollection(LinkedList::new)); Set<Atom> nonResolvableAtoms = new HashSet<>(); while (!atoms.isEmpty()) { Atom top = atoms.remove(); if (top.isRuleResolvable()) { if (!nonResolvableAtoms.isEmpty()) { queries.add(ReasonerQueries.create(nonResolvableAtoms, graph)); nonResolvableAtoms.clear(); } queries.add(ReasonerQueries.atomic(top)); } else { nonResolvableAtoms.add(top); if (atoms.isEmpty()) queries.add(ReasonerQueries.create(nonResolvableAtoms, graph)); } } return queries; } /** * compute the resolution plan - list of atomic queries ordered by their resolution priority * @return list of prioritised queries */ public static LinkedList<ReasonerQueryImpl> getResolutionPlan(ReasonerQueryImpl query) { LinkedList<ReasonerQueryImpl> queries = new LinkedList<>(); GraknGraph graph = query.graph(); LinkedList<Atom> atoms = query.selectAtoms().stream() .sorted(Comparator.comparing(at -> -at.baseResolutionPriority())) .collect(Collectors.toCollection(LinkedList::new)); Atom top = atoms.getFirst(); Set<Atom> nonResolvableAtoms = new HashSet<>(); Set<Var> subbedVars = query.getIdPredicates().stream().map(IdPredicate::getVarName) .collect(Collectors.toSet()); while (!atoms.isEmpty()) { subbedVars.addAll(top.getVarNames()); atoms.remove(top); if (top.isRuleResolvable()) { if (!nonResolvableAtoms.isEmpty()) { queries.add(ReasonerQueries.create(nonResolvableAtoms, graph)); nonResolvableAtoms.clear(); } queries.add(ReasonerQueries.atomic(top)); } else { nonResolvableAtoms.add(top); if (atoms.isEmpty()) queries.add(ReasonerQueries.create(nonResolvableAtoms, graph)); } //look at neighbours up to two hops away top = top.getNeighbours().filter(atoms::contains) .flatMap(at -> Stream.concat(Stream.of(at), at.getNeighbours().filter(atoms::contains))) .sorted(Comparator.comparing(at -> -at.computePriority(subbedVars))).findFirst().orElse(null); //top is disconnected atom if (top == null) { top = atoms.stream().sorted(Comparator.comparing(at -> -at.computePriority(subbedVars))).findFirst() .get(); } } return queries; } }