/*
* This file is part of the HyperGraphDB source distribution. This is copyrighted
* software. For permitted uses, licensing options and redistribution, please see
* the LicensingInformation file at the root level of the distribution.
*
* Copyright (c) 2005-2010 Kobrix Software, Inc. All rights reserved.
*/
package org.hypergraphdb.query.cond2qry;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import org.hypergraphdb.HGException;
import org.hypergraphdb.HGHandle;
import org.hypergraphdb.HGIndex;
import org.hypergraphdb.HGLink;
import org.hypergraphdb.HGOrderedSearchable;
import org.hypergraphdb.HGPersistentHandle;
import org.hypergraphdb.HGQuery;
import org.hypergraphdb.HGSearchResult;
import org.hypergraphdb.HGSearchable;
import org.hypergraphdb.HGSortIndex;
import org.hypergraphdb.HyperGraph;
import org.hypergraphdb.HGQuery.hg;
import org.hypergraphdb.algorithms.DefaultALGenerator;
import org.hypergraphdb.algorithms.HGBreadthFirstTraversal;
import org.hypergraphdb.atom.HGSubgraph;
import org.hypergraphdb.atom.HGSubsumes;
import org.hypergraphdb.indexing.DirectValueIndexer;
import org.hypergraphdb.query.And;
import org.hypergraphdb.query.AnyAtomCondition;
import org.hypergraphdb.query.AtomPartCondition;
import org.hypergraphdb.query.AtomProjectionCondition;
import org.hypergraphdb.query.AtomTypeCondition;
import org.hypergraphdb.query.AtomValueCondition;
import org.hypergraphdb.query.BFSCondition;
import org.hypergraphdb.query.ComparisonOperator;
import org.hypergraphdb.query.DFSCondition;
import org.hypergraphdb.query.HGAtomPredicate;
import org.hypergraphdb.query.HGQueryCondition;
import org.hypergraphdb.query.IncidentCondition;
import org.hypergraphdb.query.IndexCondition;
import org.hypergraphdb.query.IndexedPartCondition;
import org.hypergraphdb.query.IsCondition;
import org.hypergraphdb.query.LinkCondition;
import org.hypergraphdb.query.MapCondition;
import org.hypergraphdb.query.Nothing;
import org.hypergraphdb.query.Or;
import org.hypergraphdb.query.OrderedLinkCondition;
import org.hypergraphdb.query.PositionedIncidentCondition;
import org.hypergraphdb.query.SubgraphContainsCondition;
import org.hypergraphdb.query.SubgraphMemberCondition;
import org.hypergraphdb.query.SubsumedCondition;
import org.hypergraphdb.query.SubsumesCondition;
import org.hypergraphdb.query.TargetCondition;
import org.hypergraphdb.query.TypePlusCondition;
import org.hypergraphdb.query.TypedValueCondition;
import org.hypergraphdb.query.impl.HandleArrayResultSet;
import org.hypergraphdb.query.impl.IndexBasedQuery;
import org.hypergraphdb.query.impl.IndexScanQuery;
import org.hypergraphdb.query.impl.IntersectionQuery;
import org.hypergraphdb.query.impl.LinkTargetsResultSet;
import org.hypergraphdb.query.impl.PipeQuery;
import org.hypergraphdb.query.impl.PredicateBasedFilter;
import org.hypergraphdb.query.impl.ProjectionAtomResultSet;
import org.hypergraphdb.query.impl.ResultMapQuery;
import org.hypergraphdb.query.impl.SearchableBasedQuery;
import org.hypergraphdb.query.impl.SortedIntersectionResult;
import org.hypergraphdb.query.impl.TraversalBasedQuery;
import org.hypergraphdb.query.impl.UnionQuery;
//import org.hypergraphdb.query.impl.ZigZagIntersectionResult;
import org.hypergraphdb.type.HGAtomType;
import org.hypergraphdb.util.ArrayBasedSet;
import org.hypergraphdb.util.Pair;
import org.hypergraphdb.util.Ref;
@SuppressWarnings("unchecked")
public class ToQueryMap extends HashMap<Class<?>, ConditionToQuery>
{
private static final long serialVersionUID = -1;
protected static final ToQueryMap instance = new ToQueryMap();
static
{
instance.put(Nothing.class, new ConditionToQuery()
{
public HGQuery<?> getQuery(HyperGraph graph, HGQueryCondition c)
{
return HGQuery.NOP;
}
public QueryMetaData getMetaData(HyperGraph hg, HGQueryCondition c)
{
return QueryMetaData.EMPTY;
}
});
instance.put(AnyAtomCondition.class, new ConditionToQuery()
{
public HGQuery<?> getQuery(HyperGraph graph, HGQueryCondition c)
{
return new IndexScanQuery(graph.getIndexManager().getIndexByType(), false);
}
public QueryMetaData getMetaData(HyperGraph hg, HGQueryCondition c)
{
QueryMetaData x = QueryMetaData.MISTERY.clone(c);
x.predicateCost = 0.5;
return x;
}
});
instance.put(AtomTypeCondition.class, new ConditionToQuery()
{
private HGPersistentHandle getTypeHandle(HyperGraph graph, HGQueryCondition c)
{
AtomTypeCondition ac = (AtomTypeCondition)c;
HGHandle h = ac.getTypeHandle();
if (h == null)
h = graph.getTypeSystem().getTypeHandle(ac.getJavaClass());
return graph.getPersistentHandle(h);
}
public HGQuery<?> getQuery(final HyperGraph graph, HGQueryCondition c)
{
final AtomTypeCondition ac = (AtomTypeCondition)c;
if (!hg.isVar(ac.getTypeReference()) && ac.getTypeHandle() == null &&
graph.getTypeSystem().getTypeHandleIfDefined(ac.getJavaClass()) == null)
return HGQuery.NOP;
return new SearchableBasedQuery(graph.getIndexManager().getIndexByType(),
new Ref<HGPersistentHandle>() {
public HGPersistentHandle get()
{
return ac.getTypeHandle(graph).getPersistent();
}},
ComparisonOperator.EQ);
}
public QueryMetaData getMetaData(HyperGraph graph, HGQueryCondition c)
{
AtomTypeCondition ac = (AtomTypeCondition)c;
QueryMetaData x = QueryMetaData.ORACCESS.clone(c);
x.predicateCost = 1;
if (hg.isVar(ac.getTypeReference()))
{
// TODO: maybe we can get better estimates here if we collect some global
// database statistics, e.g. in the HGStats bean
// x.sizeExpected = ...
// x.sizeLB = ...
// x.sizeUB = ..
}
else
{
x.sizeExpected =
x.sizeLB =
x.sizeUB = graph.getIndexManager().getIndexByType().count(ac.getTypeHandle(graph).getPersistent());
}
return x;
}
});
instance.put(TypePlusCondition.class, new ConditionToQuery()
{
public HGQuery<?> getQuery(HyperGraph hg, HGQueryCondition c)
{
TypePlusCondition ac = (TypePlusCondition)c;
Or orCondition = new Or();
for (HGHandle h : ac.getSubTypes(hg))
orCondition.add(new AtomTypeCondition(h));
return HGQuery.make(hg, orCondition); //instance.get(Or.class).getQuery(hg, orCondition);
}
public QueryMetaData getMetaData(HyperGraph hg, HGQueryCondition c)
{
TypePlusCondition ac = (TypePlusCondition)c;
Or orCondition = new Or();
for (HGHandle h : ac.getSubTypes(hg))
orCondition.add(new AtomTypeCondition(h));
return toMetaData(hg, orCondition); //instance.get(Or.class).getMetaData(hg, orCondition);
}
});
instance.put(TypedValueCondition.class, new TypedValueToQuery());
instance.put(AtomValueCondition.class, new ConditionToQuery()
{
HGQuery<Object> makeQuery(HyperGraph graph, Object value, ComparisonOperator op)
{
if (value == null)
throw new HGException("Search by null values is not supported yet.");
HGHandle type = graph.getTypeSystem().getTypeHandle(value);
Pair<HGHandle, HGIndex> p = ExpressionBasedQuery.findIndex(graph, new DirectValueIndexer<Object>(type));
if (p != null)
return (HGQuery<Object>)instance.get(IndexCondition.class).
getQuery(graph, new IndexCondition(p.getSecond(), value, op));
else
return (HGQuery<Object>)instance.get(TypedValueCondition.class).
getQuery(graph, new TypedValueCondition(type,
value,
op));
}
public HGQuery<?> getQuery(final HyperGraph graph, final HGQueryCondition c)
{
//
// TODO: how to we deal with null values? For the String
// primitive type at least, nulls are possible. We can only deal
// with nulls if the type is know in which case a TypedValueCondition
// must have been used.
//
final AtomValueCondition vc = (AtomValueCondition)c;
if (hg.isVar(vc.getValueReference()))
return new HGQuery<Object>() {
public HGSearchResult<Object> execute()
{
return makeQuery(graph, vc.getValue(), vc.getOperator()).execute();
}
};
else
return makeQuery(graph, vc.getValue(), vc.getOperator());
}
public QueryMetaData getMetaData(HyperGraph graph, HGQueryCondition c)
{
AtomValueCondition vc = (AtomValueCondition)c;
if (hg.isVar(vc.getValueReference()))
return QueryMetaData.MISTERY;
Object value = vc.getValue();
if (value == null)
throw new HGException("Search by null values is not supported yet.");
HGHandle type = graph.getTypeSystem().getTypeHandle(value);
return instance.get(TypedValueCondition.class).
getMetaData(graph, new TypedValueCondition(type,
vc.getValue(),
vc.getOperator()));
}
});
instance.put(ValueAsPredicateOnly.class, new ConditionToQuery()
{
public HGQuery<?> getQuery(HyperGraph hg, HGQueryCondition c)
{
return null;
}
public QueryMetaData getMetaData(HyperGraph hg, HGQueryCondition c)
{
QueryMetaData qmd = QueryMetaData.MISTERY.clone();
qmd.predicateOnly = true;
qmd.pred = (HGAtomPredicate)c;
return qmd;
}
});
instance.put(TargetCondition.class, new ConditionToQuery()
{
public HGQuery<HGHandle> getQuery(final HyperGraph graph, final HGQueryCondition c)
{
return new HGQuery<HGHandle>()
{
public HGSearchResult<HGHandle> execute()
{
final HGPersistentHandle handle = ((TargetCondition)c).getLink().getPersistent();
if (graph.isLoaded(handle))
return new LinkTargetsResultSet((HGLink)graph.get(handle));
else
{
HGPersistentHandle [] A = graph.getStore().getLink(handle);
if (A == null)
throw new NullPointerException("No link data for handle " + handle);
return new HandleArrayResultSet(A, 2);
}
}
};
}
public QueryMetaData getMetaData(HyperGraph hg, HGQueryCondition c)
{
QueryMetaData x = QueryMetaData.MISTERY.clone(c);
x.predicateCost = 1;
return x;
}
});
instance.put(IncidentCondition.class, new IncidentToQuery());
instance.put(PositionedIncidentCondition.class, new PositionedIncidentToQuery());
instance.put(LinkCondition.class, new LinkToQuery());
instance.put(SubsumesCondition.class, new ConditionToQuery()
{
public HGQuery getQuery(HyperGraph hg, HGQueryCondition c)
{
SubsumesCondition sc = (SubsumesCondition)c;
Ref<HGHandle> startAtom = sc.getSpecificHandleReference();
if (startAtom == null && sc.getSpecificValue() != null)
{
throw new HGException("Unable to translate 'subsumed' condition into a query, please a handle for the specific entity.");
}
return new TraversalBasedQuery(
new HGBreadthFirstTraversal(
startAtom,
new DefaultALGenerator(hg,
new AtomTypeCondition(hg.getTypeSystem().getTypeHandle(HGSubsumes.class)),
null,
false,
true,
true),
Integer.MAX_VALUE
), TraversalBasedQuery.ReturnType.targets);
}
public QueryMetaData getMetaData(HyperGraph hg, HGQueryCondition c)
{
QueryMetaData x = QueryMetaData.MISTERY.clone(c);
// this is kind of approx. as the predicate may return very quickly
// or end up doing an all separate query on its own
x.predicateCost = 5;
return x;
}
});
instance.put(BFSCondition.class, new ConditionToQuery()
{
public HGQuery getQuery(HyperGraph graph, HGQueryCondition c)
{
BFSCondition cc = (BFSCondition)c;
return new TraversalBasedQuery(cc.getTraversal(graph), TraversalBasedQuery.ReturnType.targets);
}
public QueryMetaData getMetaData(HyperGraph hg, HGQueryCondition c)
{
QueryMetaData x = QueryMetaData.MISTERY.clone(c);
x.predicateCost = -1;
x.predicateOnly = false;
return x;
}
});
instance.put(DFSCondition.class, new ConditionToQuery()
{
public HGQuery getQuery(HyperGraph graph, HGQueryCondition c)
{
DFSCondition cc = (DFSCondition)c;
return new TraversalBasedQuery(cc.getTraversal(graph), TraversalBasedQuery.ReturnType.targets);
}
public QueryMetaData getMetaData(HyperGraph hg, HGQueryCondition c)
{
return QueryMetaData.MISTERY.clone(c);
}
});
instance.put(SubsumedCondition.class, new ConditionToQuery()
{
public HGQuery getQuery(HyperGraph hg, HGQueryCondition c)
{
SubsumedCondition sc = (SubsumedCondition)c;
Ref<HGHandle> startAtom = sc.getGeneralHandleReference();
if (startAtom == null && sc.getGeneralValue() != null)
{
throw new HGException("Unable to translate 'subsumed' condition into a query, please use a valid handle for the general entity.");
}
return new TraversalBasedQuery(
new HGBreadthFirstTraversal(
startAtom,
new DefaultALGenerator(hg,
new AtomTypeCondition(hg.getTypeSystem().getTypeHandle(HGSubsumes.class)),
null,
false,
true,
false),
Integer.MAX_VALUE
), TraversalBasedQuery.ReturnType.targets);
}
public QueryMetaData getMetaData(HyperGraph hg, HGQueryCondition c)
{
QueryMetaData x = QueryMetaData.MISTERY.clone(c);
// this is kind of approx. as the predicate may return very quickly
// or end up doing an all separate query on its own
x.predicateCost = 5;
return x;
}
});
instance.put(OrderedLinkCondition.class, new ConditionToQuery()
{
public HGQuery<?> getQuery(HyperGraph hg, HGQueryCondition c)
{
OrderedLinkCondition lc = (OrderedLinkCondition)c;
ArrayList<HGQuery<?>> L = new ArrayList<HGQuery<?>>();
for (Ref<HGHandle> t : lc.targets())
L.add(toQuery(hg, new IncidentCondition(t)));
if (L.isEmpty())
return HGQuery.NOP;
else if (L.size() == 1)
return L.get(0);
else
{
Iterator<HGQuery<?>> i = L.iterator();
IntersectionQuery result = new IntersectionQuery(i.next(),
i.next(),
new SortedIntersectionResult.Combiner<HGHandle>());
while (i.hasNext())
result = new IntersectionQuery(i.next(),
result,
new SortedIntersectionResult.Combiner<HGHandle>());
// the following will find all links (unordered) with the given target
// set and then filter to insure that the targets are properly ordered.
return new PredicateBasedFilter<HGHandle>(hg, result, lc);
}
}
public QueryMetaData getMetaData(HyperGraph hg, HGQueryCondition c)
{
QueryMetaData qmd;
if (((OrderedLinkCondition)c).targets().length == 0)
qmd = QueryMetaData.EMPTY.clone(c);
else
qmd = QueryMetaData.MISTERY.clone(c);
qmd.predicateCost = 0.5;
return qmd;
}
});
instance.put(MapCondition.class, new ConditionToQuery()
{
public HGQuery getQuery(HyperGraph hg, HGQueryCondition c)
{
MapCondition mc = (MapCondition)c;
HGQuery query = toQuery(hg, mc.getCondition());
return new ResultMapQuery(query, mc.getMapping());
}
public QueryMetaData getMetaData(HyperGraph hg, HGQueryCondition c)
{
MapCondition mc = (MapCondition)c;
QueryMetaData qmd = instance.get(mc.getCondition().getClass()).getMetaData(hg, mc.getCondition());
qmd.randomAccess = false;
qmd.ordered = false; // should we have an order preserving mapping?
qmd.predicateCost = -1;
qmd.cond = c;
return qmd;
}
});
instance.put(IndexCondition.class, new ConditionToQuery()
{
public HGQuery<?> getQuery(HyperGraph graph, HGQueryCondition c)
{
IndexCondition ic = (IndexCondition)c;
if (ic.getOperator() != ComparisonOperator.EQ)
{
if (! (ic.getIndex() instanceof HGSortIndex))
throw new IllegalArgumentException("Invalid operator : " + ic.getOperator() +
" for index " + ic.getIndex() + " and key " + ic.getKey());
else
return new IndexBasedQuery(ic.getIndex(), ic.getKeyReference(), ic.getOperator());
}
else
return new IndexBasedQuery(ic.getIndex(), ic.getKeyReference(), ComparisonOperator.EQ);
}
public QueryMetaData getMetaData(HyperGraph hg, HGQueryCondition c)
{
IndexCondition ic = (IndexCondition)c;
if (ic.getOperator() == ComparisonOperator.EQ)
return QueryMetaData.ORACCESS.clone(c);
else
{
QueryMetaData qmd = QueryMetaData.MISTERY.clone(c);
return qmd;
}
}
});
instance.put(IndexedPartCondition.class, new ConditionToQuery()
{
public HGQuery<?> getQuery(HyperGraph hg, HGQueryCondition c)
{
IndexedPartCondition ip = (IndexedPartCondition)c;
if (ip.getIndex() instanceof HGSortIndex)
return new IndexBasedQuery((HGSortIndex)ip.getIndex(),
ip.getPartValueReference(),
ip.getOperator());
else
return new IndexBasedQuery(ip.getIndex(), ip.getPartValueReference());
}
public QueryMetaData getMetaData(HyperGraph hg, HGQueryCondition c)
{
return QueryMetaData.ORACCESS.clone(c);
}
});
instance.put(And.class, new AndToQuery());
instance.put(Or.class, new ConditionToQuery()
{
public HGQuery getQuery(HyperGraph hg, HGQueryCondition c)
{
Or or = (Or)c;
if (or.size() == 0)
return HGQuery.NOP;
else if (or.size() == 1)
return toQuery(hg, or.get(0));
// TODO - we need to do better, even for this sloppy algorithm, we can
// can try to factor out common conditions in conjunctions, make sure
// all conjunction end up in a treatable form (ordered or randomAccess) etc.
HGQuery q1 = toQuery(hg, or.get(0));
if (q1 == null)
throw new HGException("Untranslatable condition " + or.get(0));
HGQuery q2 = toQuery(hg, or.get(1));
if (q2 == null)
throw new HGException("Untranslatable condition " + or.get(1));
UnionQuery result = new UnionQuery(q1, q2);
for (int i = 2; i < or.size(); i++)
{
q1 = toQuery(hg, or.get(i));
if (q1 == null)
throw new HGException("Untranslatable condition " + or.get(i));
result = new UnionQuery(result, q1);
}
return result;
}
public QueryMetaData getMetaData(HyperGraph hg, HGQueryCondition c)
{
QueryMetaData x = QueryMetaData.ORDERED.clone(c);
boolean ispredicate = true;
x.predicateCost = 0;
for (HGQueryCondition sub : ((Or)c))
{
if (! (sub instanceof HGAtomPredicate))
ispredicate = false;
ConditionToQuery transformer = instance.get(sub.getClass());
if (transformer == null)
{
if (! (sub instanceof HGAtomPredicate))
throw new HGException("Condition " + sub + " is not query translatable, nor a predicate.");
else
{
x.ordered = false;
x.randomAccess = false;
continue;
}
}
QueryMetaData subx = transformer.getMetaData(hg, sub);
ispredicate = ispredicate && subx.predicateCost > -1;
x.predicateCost += subx.predicateCost;
x.ordered = x.ordered && subx.ordered;
x.randomAccess = x.randomAccess && subx.randomAccess;
}
if (!ispredicate)
x.predicateCost = -1;
else
x.predicateCost /= ((Or)c).size();
return x;
}
});
instance.put(AtomPartCondition.class, new ConditionToQuery()
{
public HGQuery getQuery(HyperGraph hg, HGQueryCondition c)
{
// AtomPartCondition apc = (AtomPartCondition)c;
// throw new HGException("Can't use an AtomPartCondition alone, please restrict your query by atom type or other general criteria.");
return null;
}
public QueryMetaData getMetaData(HyperGraph hg, HGQueryCondition c)
{
// throw new HGException("Can't use an AtomPartCondition alone, please restrict your query by atom type or other general criteria.");
QueryMetaData qmd = QueryMetaData.MISTERY.clone(c);
qmd.predicateCost = 1.5;
qmd.predicateOnly = true;
return qmd;
}
});
instance.put(AtomProjectionCondition.class, new ConditionToQuery()
{
public HGQuery getQuery(final HyperGraph graph, final HGQueryCondition c)
{
final AtomProjectionCondition apc = (AtomProjectionCondition)c;
final HGQueryCondition bc = apc.getBaseSetCondition();
HGHandle type = null;
// Special case that can be handled slightly more efficiently when the referent type is known:
if (bc instanceof AtomTypeCondition)
type = ((AtomTypeCondition)bc).getTypeHandle();
final HGHandle baseType = type;
return new HGQuery()
{
public HGSearchResult execute()
{
HGQuery q = toQuery(graph, bc);
return new ProjectionAtomResultSet(graph,
q.execute(),
apc.getDimensionPath(),
baseType);
}
};
}
public QueryMetaData getMetaData(HyperGraph hg, HGQueryCondition c)
{
QueryMetaData x = QueryMetaData.MISTERY.clone(c);
x.predicateCost = 100; // this is because they will be a query involved in the predicate etc...expensive stuff
return x;
}
});
instance.put(SubgraphMemberCondition.class, new ConditionToQuery()
{
public QueryMetaData getMetaData(HyperGraph graph,
HGQueryCondition condition)
{
return QueryMetaData.ORACCESS.clone(condition);
}
public HGQuery<?> getQuery(final HyperGraph graph,
final HGQueryCondition condition)
{
return new HGQuery<HGPersistentHandle>()
{
public HGSearchResult<HGPersistentHandle> execute()
{
HGIndex<HGPersistentHandle, HGPersistentHandle> idx = HGSubgraph.getIndex(graph);
return idx.find(((SubgraphMemberCondition)condition).getSubgraphHandle().getPersistent());
}
};
}
});
instance.put(SubgraphContainsCondition.class, new ConditionToQuery()
{
public QueryMetaData getMetaData(HyperGraph graph,
HGQueryCondition condition)
{
return QueryMetaData.ORACCESS.clone(condition);
}
public HGQuery<?> getQuery(final HyperGraph graph,
final HGQueryCondition condition)
{
return new HGQuery<HGPersistentHandle>()
{
public HGSearchResult<HGPersistentHandle> execute()
{
HGIndex<HGPersistentHandle, HGPersistentHandle> idx = HGSubgraph.getReverseIndex(graph);
return idx.find(((SubgraphContainsCondition)condition).getAtom().getPersistent());
}
};
}
});
instance.put(IsCondition.class, new ConditionToQuery()
{
public QueryMetaData getMetaData(HyperGraph graph, HGQueryCondition condition)
{
return QueryMetaData.ORACCESS.clone(condition);
}
public HGQuery<?> getQuery(final HyperGraph graph, final HGQueryCondition condition)
{
return new HGQuery<HGPersistentHandle>()
{
public HGSearchResult<HGPersistentHandle> execute()
{
HGHandle h = ((IsCondition)condition).getAtomHandle();
ArrayBasedSet A = new ArrayBasedSet(new HGHandle[] {h});
return A.getSearchResult();
}
};
}
});
}
public static ToQueryMap getInstance() { return instance; }
static <ResultType> HGQuery<ResultType> toQuery(HyperGraph hg, HGQueryCondition condition)
{
ConditionToQuery transformer = (ConditionToQuery)instance.get(condition.getClass());
if (transformer == null)
throw new HGException("The query condition '" + condition +
"' could not be translated to an executable query either because it is not specific enough. " +
"Please try to contrain the query futher, for example by specifying the atom's types or " +
"incidence sets or some indexed property value.");
else
{
HGQuery<ResultType> q = (HGQuery<ResultType>)transformer.getQuery(hg, condition);
if (q == null)
throw new IllegalArgumentException("Unable to convert query condition " +
condition + " to a query. Try constraining further, e.g. by atom type.");
q.setHyperGraph(hg);
return q;
}
}
protected static QueryMetaData toMetaData(HyperGraph hg, HGQueryCondition condition)
{
ConditionToQuery transformer = (ConditionToQuery)instance.get(condition.getClass());
if (transformer == null)
throw new HGException("The query condition '" + condition +
"' could not be translated to an executable query because it is not specific enough. " +
"Please try to contrain the query futher, for example by specifying the atom's types or " +
"incidence sets or some indexed property value.");
else
return transformer.getMetaData(hg, condition);
}
}