private ListMultimap<String, TextHit> query( Node property, String queryString, int limit, ExecutionContext execCxt) { // use the graph information in the text index if possible if (textIndex.getDocDef().getGraphField() != null && execCxt.getActiveGraph() instanceof GraphView) { GraphView activeGraph = (GraphView) execCxt.getActiveGraph(); if (!Quad.isUnionGraph(activeGraph.getGraphName())) { String uri = activeGraph.getGraphName() != null ? TextQueryFuncs.graphNodeToString(activeGraph.getGraphName()) : Quad.defaultGraphNodeGenerated.getURI(); String escaped = QueryParserBase.escape(uri); String qs2 = textIndex.getDocDef().getGraphField() + ":" + escaped; queryString = "(" + queryString + ") AND " + qs2; } } // for language-based search extension if (textIndex.getDocDef().getLangField() != null) { String field = textIndex.getDocDef().getLangField(); if (langArg != null) { String qs2 = !"none".equals(langArg) ? field + ":" + langArg : "-" + field + ":*"; queryString = "(" + queryString + ") AND " + qs2; } } Explain.explain(execCxt.getContext(), "Text query: " + queryString); if (log.isDebugEnabled()) log.debug("Text query: {} ({})", queryString, limit); String cacheKey = limit + " " + property + " " + queryString; Cache<String, ListMultimap<String, TextHit>> queryCache = (Cache<String, ListMultimap<String, TextHit>>) execCxt.getContext().get(cacheSymbol); if (queryCache == null) { /* doesn't yet exist, need to create it */ queryCache = CacheFactory.createCache(CACHE_SIZE); execCxt.getContext().put(cacheSymbol, queryCache); } final String queryStr = queryString; // final needed for the lambda function ListMultimap<String, TextHit> results = queryCache.getOrFill( cacheKey, () -> { List<TextHit> resultList = textIndex.query(property, queryStr, limit); ListMultimap<String, TextHit> resultMultimap = LinkedListMultimap.create(); for (TextHit result : resultList) { resultMultimap.put(result.getNode().getURI(), result); } return resultMultimap; }); return results; }
@Override public void build( PropFuncArg argSubject, Node predicate, PropFuncArg argObject, ExecutionContext execCxt) { super.build(argSubject, predicate, argObject, execCxt); DatasetGraph dsg = execCxt.getDataset(); textIndex = chooseTextIndex(dsg); if (argSubject.isList()) { int size = argSubject.getArgListSize(); if (size != 2 && size != 3) { throw new QueryBuildException( "Subject has " + argSubject.getArgList().size() + " elements, not 2 or 3: " + argSubject); } } if (argObject.isList()) { List<Node> list = argObject.getArgList(); if (list.size() == 0) throw new QueryBuildException("Zero-length argument list"); if (list.size() > 4) throw new QueryBuildException("Too many arguments in list : " + list); // extract of extra lang arg if present and if is usable. // arg is removed from the list to avoid conflict with order and args length langArg = extractArg("lang", list); if (langArg != null && textIndex.getDocDef().getLangField() == null) log.warn("lang argument is ignored if langField not set in the index configuration"); } }
@Override public QueryIterator execOneList( Binding binding, Node listNode, Node predicate, Node length, ExecutionContext execCxt) { Graph graph = execCxt.getActiveGraph(); if (Var.isVar(listNode)) throw new ARQInternalErrorException("listLength: Subject is a variable"); // Case : arg 1 (the list) is bound and arg 2 not bound => generate possibilities // Case : arg 1 is bound and arg 2 is bound => test for membership. if (Var.isVar(length)) return length(binding, graph, listNode, Var.alloc(length), execCxt); else return verify(binding, graph, listNode, length, execCxt); }
@Override public QueryIterator exec( Binding binding, PropFuncArg argSubject, Node predicate, PropFuncArg argObject, ExecutionContext execCxt) { if (textIndex == null) { if (!warningIssued) { Log.warn(getClass(), "No text index - no text search performed"); warningIssued = true; } // Not a text dataset - no-op return IterLib.result(binding, execCxt); } DatasetGraph dsg = execCxt.getDataset(); argSubject = Substitute.substitute(argSubject, binding); argObject = Substitute.substitute(argObject, binding); Node s = null; Node score = null; Node literal = null; if (argSubject.isList()) { // Length checked in build() s = argSubject.getArg(0); score = argSubject.getArg(1); if (!score.isVariable()) throw new QueryExecException("Hit score is not a variable: " + argSubject); if (argSubject.getArgListSize() > 2) { literal = argSubject.getArg(2); if (!literal.isVariable()) throw new QueryExecException("Hit literal is not a variable: " + argSubject); } } else { s = argSubject.getArg(); } if (s.isLiteral()) // Does not match return IterLib.noResults(execCxt); StrMatch match = objectToStruct(argObject, true); if (match == null) { // can't match return IterLib.noResults(execCxt); } // ---- QueryIterator qIter = (Var.isVar(s)) ? variableSubject(binding, s, score, literal, match, execCxt) : concreteSubject(binding, s, score, literal, match, execCxt); if (match.getLimit() >= 0) qIter = new QueryIterSlice(qIter, 0, match.getLimit(), execCxt); return qIter; }
@Override protected QueryIterator execObjectBound( Binding binding, Var listVar, Node predicate, Node length, ExecutionContext execCxt) { Graph graph = execCxt.getActiveGraph(); return length(binding, graph, listVar, Var.alloc(length), execCxt); }