Search in sources :

Example 46 with NodeSet

use of org.exist.dom.persistent.NodeSet in project exist by eXist-db.

the class GeneralComparison method quickNodeSetCompare.

/**
 * Optimized implementation: first checks if a range index is defined on the nodes in the left argument.
 * Otherwise, fall back to {@link #nodeSetCompare(NodeSet, Sequence)}.
 *
 * @param   contextSequence  DOCUMENT ME!
 *
 * @return  DOCUMENT ME!
 *
 * @throws  XPathException  DOCUMENT ME!
 */
protected Sequence quickNodeSetCompare(Sequence contextSequence) throws XPathException {
    if (context.getProfiler().isEnabled()) {
        context.getProfiler().message(this, Profiler.OPTIMIZATION_FLAGS, "OPTIMIZATION CHOICE", "quickNodeSetCompare");
    }
    final long start = System.currentTimeMillis();
    // get the NodeSet on the left
    final Sequence leftSeq = getLeft().eval(contextSequence);
    if (!leftSeq.isPersistentSet()) {
        return (genericCompare(leftSeq, contextSequence, null));
    }
    final NodeSet nodes = leftSeq.isEmpty() ? NodeSet.EMPTY_SET : (NodeSet) leftSeq;
    // nothing on the left, so nothing to do
    if (!(nodes instanceof VirtualNodeSet) && nodes.isEmpty()) {
        // Well, we might discuss this one ;-)
        hasUsedIndex = true;
        return (Sequence.EMPTY_SEQUENCE);
    }
    // get the Sequence on the right
    final Sequence rightSeq = getRight().eval(contextSequence);
    // nothing on the right, so nothing to do
    if (rightSeq.isEmpty()) {
        // Well, we might discuss this one ;-)
        hasUsedIndex = true;
        return (Sequence.EMPTY_SEQUENCE);
    }
    // get the type of a possible index
    final int indexType = nodes.getIndexType();
    // remember that Type.ITEM means... no index ;-)
    if (indexType != Type.ITEM) {
        if (LOG.isTraceEnabled()) {
            LOG.trace("found an index of type: {}", Type.getTypeName(indexType));
        }
        boolean indexScan = false;
        boolean indexMixed = false;
        QName myContextQName = contextQName;
        if (contextSequence != null) {
            final IndexFlags iflags = checkForQNameIndex(idxflags, context, contextSequence, myContextQName);
            boolean indexFound = false;
            if (!iflags.indexOnQName) {
                // if myContextQName != null and no index is defined on
                // myContextQName, we don't need to scan other QName indexes
                // and can just use the generic range index
                indexFound = myContextQName != null;
                if (iflags.partialIndexOnQName) {
                    indexMixed = true;
                } else {
                    // set myContextQName to null so the index lookup below is not
                    // restricted to that QName
                    myContextQName = null;
                }
            }
            if (!indexFound && (myContextQName == null)) {
                // we need to check them all
                if (iflags.hasIndexOnQNames) {
                    indexScan = true;
                }
            // else use range index defined on path by default
            }
        } else {
            return (nodeSetCompare(nodes, contextSequence));
        }
        // Get the documents from the node set
        final DocumentSet docs = nodes.getDocumentSet();
        // Holds the result
        NodeSet result = null;
        // Iterate through the right hand sequence
        for (final SequenceIterator itRightSeq = Atomize.atomize(rightSeq).iterate(); itRightSeq.hasNext(); ) {
            // Get the index key
            Item key = itRightSeq.nextItem();
            // if key has truncation, convert it to string
            if (truncation != StringTruncationOperator.NONE) {
                if (!Type.subTypeOf(key.getType(), Type.STRING)) {
                    LOG.info("Truncated key. Converted from {} to xs:string", Type.getTypeName(key.getType()));
                    // truncation is only possible on strings
                    key = key.convertTo(Type.STRING);
                }
            } else // TODO : use Type.isSubType() ??? -pb
            if (key.getType() != indexType) {
                // try to convert the key to the index type
                try {
                    key = key.convertTo(indexType);
                } catch (final XPathException xpe) {
                    // Could not convert the key to a suitable type for the index, fallback to nodeSetCompare()
                    if (context.getProfiler().isEnabled()) {
                        context.getProfiler().message(this, Profiler.OPTIMIZATION_FLAGS, "OPTIMIZATION FALLBACK", "Falling back to nodeSetCompare (" + xpe.getMessage() + ")");
                    }
                    if (LOG.isTraceEnabled()) {
                        LOG.trace("Cannot convert key: {} to required index type: {}", Type.getTypeName(key.getType()), Type.getTypeName(indexType));
                    }
                    return (nodeSetCompare(nodes, contextSequence));
                }
            }
            // If key implements org.exist.storage.Indexable, we can use the index
            if (key instanceof Indexable) {
                if (LOG.isTraceEnabled()) {
                    LOG.trace("Checking if range index can be used for key: {}", key.getStringValue());
                }
                final Collator collator = ((collationArg != null) ? getCollator(contextSequence) : null);
                if (Type.subTypeOf(key.getType(), indexType)) {
                    if (truncation == StringTruncationOperator.NONE) {
                        if (LOG.isTraceEnabled()) {
                            LOG.trace("Using range index for key: {}", key.getStringValue());
                        }
                        // key without truncation, find key
                        context.getProfiler().message(this, Profiler.OPTIMIZATIONS, "OPTIMIZATION", "Using value index '" + context.getBroker().getValueIndex().toString() + "' to find key '" + Type.getTypeName(key.getType()) + "(" + key.getStringValue() + ")'");
                        NodeSet ns;
                        if (indexScan) {
                            ns = context.getBroker().getValueIndex().findAll(context.getWatchDog(), relation, docs, nodes, NodeSet.ANCESTOR, (Indexable) key);
                        } else {
                            ns = context.getBroker().getValueIndex().find(context.getWatchDog(), relation, docs, nodes, NodeSet.ANCESTOR, myContextQName, (Indexable) key, indexMixed);
                        }
                        hasUsedIndex = true;
                        if (result == null) {
                            result = ns;
                        } else {
                            result = result.union(ns);
                        }
                    } else {
                        // key with truncation, match key
                        if (LOG.isTraceEnabled()) {
                            context.getProfiler().message(this, Profiler.OPTIMIZATIONS, "OPTIMIZATION", "Using value index '" + context.getBroker().getValueIndex().toString() + "' to match key '" + Type.getTypeName(key.getType()) + "(" + key.getStringValue() + ")'");
                        }
                        if (LOG.isTraceEnabled()) {
                            LOG.trace("Using range index for key: {}", key.getStringValue());
                        }
                        try {
                            NodeSet ns;
                            final String matchString = key.getStringValue();
                            final int matchType = getMatchType(truncation);
                            if (indexScan) {
                                ns = context.getBroker().getValueIndex().matchAll(context.getWatchDog(), docs, nodes, NodeSet.ANCESTOR, matchString, matchType, 0, true, collator, truncation);
                            } else {
                                ns = context.getBroker().getValueIndex().match(context.getWatchDog(), docs, nodes, NodeSet.ANCESTOR, matchString, myContextQName, matchType, collator, truncation);
                            }
                            hasUsedIndex = true;
                            if (result == null) {
                                result = ns;
                            } else {
                                result = result.union(ns);
                            }
                        } catch (final EXistException e) {
                            throw (new XPathException(this, e));
                        }
                    }
                } else {
                    // our key does is not of the correct type
                    if (context.getProfiler().isEnabled()) {
                        context.getProfiler().message(this, Profiler.OPTIMIZATION_FLAGS, "OPTIMIZATION FALLBACK", "Falling back to nodeSetCompare (key is of type: " + Type.getTypeName(key.getType()) + ") whereas index is of type '" + Type.getTypeName(indexType) + "'");
                    }
                    if (LOG.isTraceEnabled()) {
                        LOG.trace("Cannot use range index: key is of type: {}) whereas index is of type '{}", Type.getTypeName(key.getType()), Type.getTypeName(indexType));
                    }
                    return (nodeSetCompare(nodes, contextSequence));
                }
            } else {
                // our key does not implement org.exist.storage.Indexable
                if (context.getProfiler().isEnabled()) {
                    context.getProfiler().message(this, Profiler.OPTIMIZATION_FLAGS, "OPTIMIZATION FALLBACK", "Falling back to nodeSetCompare (key is not an indexable type: " + key.getClass().getName());
                }
                if (LOG.isTraceEnabled()) {
                    LOG.trace("Cannot use key which is of type '{}", key.getClass().getName());
                }
                return (nodeSetCompare(nodes, contextSequence));
            }
        }
        if (context.getProfiler().traceFunctions()) {
            context.getProfiler().traceIndexUsage(context, PerformanceStats.RANGE_IDX_TYPE, this, PerformanceStats.BASIC_INDEX, System.currentTimeMillis() - start);
        }
        return (result);
    } else {
        if (LOG.isTraceEnabled()) {
            LOG.trace("No suitable index found for key: {}", rightSeq.getStringValue());
        }
        // no range index defined on the nodes in this sequence, so fallback to nodeSetCompare
        if (context.getProfiler().isEnabled()) {
            context.getProfiler().message(this, Profiler.OPTIMIZATION_FLAGS, "OPTIMIZATION FALLBACK", "falling back to nodeSetCompare (no index available)");
        }
        return (nodeSetCompare(nodes, contextSequence));
    }
}
Also used : NodeSet(org.exist.dom.persistent.NodeSet) VirtualNodeSet(org.exist.dom.persistent.VirtualNodeSet) NewArrayNodeSet(org.exist.dom.persistent.NewArrayNodeSet) QName(org.exist.dom.QName) Sequence(org.exist.xquery.value.Sequence) EXistException(org.exist.EXistException) VirtualNodeSet(org.exist.dom.persistent.VirtualNodeSet) Collator(com.ibm.icu.text.Collator) Item(org.exist.xquery.value.Item) ContextItem(org.exist.dom.persistent.ContextItem) SequenceIterator(org.exist.xquery.value.SequenceIterator) Indexable(org.exist.storage.Indexable) DocumentSet(org.exist.dom.persistent.DocumentSet)

Example 47 with NodeSet

use of org.exist.dom.persistent.NodeSet in project exist by eXist-db.

the class OpOr method eval.

public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException {
    if (context.getProfiler().isEnabled()) {
        context.getProfiler().start(this);
        context.getProfiler().message(this, Profiler.DEPENDENCIES, "DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies()));
        if (contextSequence != null) {
            context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT SEQUENCE", contextSequence);
        }
        if (contextItem != null) {
            context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT ITEM", contextItem.toSequence());
        }
    }
    if (getLength() == 0) {
        return Sequence.EMPTY_SEQUENCE;
    }
    if (contextItem != null) {
        contextSequence = contextItem.toSequence();
    }
    boolean doOptimize = optimize;
    if (contextSequence != null && !contextSequence.isPersistentSet()) {
        doOptimize = false;
    }
    Sequence result;
    final Expression left = getLeft();
    final Expression right = getRight();
    final Sequence ls = left.eval(contextSequence, null);
    // first check if left operand is a persistent set
    doOptimize = doOptimize && (ls.isPersistentSet() || ls.isEmpty());
    if (doOptimize) {
        final Sequence rs = right.eval(contextSequence, null);
        if (inPredicate) {
            NodeSet lr = ls.toNodeSet();
            lr = lr.getContextNodes(getContextId());
            NodeSet rr = rs.toNodeSet();
            rr = rr.getContextNodes(contextId);
            result = lr.union(rr);
        } else {
            // fall back
            final boolean rl = ls.effectiveBooleanValue();
            if (rl) {
                result = BooleanValue.TRUE;
            } else {
                final boolean rr = rs.effectiveBooleanValue();
                result = rl || rr ? BooleanValue.TRUE : BooleanValue.FALSE;
            }
        }
    } else {
        // no: default evaluation based on boolean value
        final boolean rl = ls.effectiveBooleanValue();
        if (rl) {
            result = BooleanValue.TRUE;
        } else {
            final Sequence rs = right.eval(contextSequence, null);
            final boolean rr = rs.effectiveBooleanValue();
            result = rl || rr ? BooleanValue.TRUE : BooleanValue.FALSE;
        }
    }
    if (context.getProfiler().isEnabled()) {
        context.getProfiler().end(this, "", result);
    }
    return result;
}
Also used : NodeSet(org.exist.dom.persistent.NodeSet) Sequence(org.exist.xquery.value.Sequence)

Example 48 with NodeSet

use of org.exist.dom.persistent.NodeSet in project exist by eXist-db.

the class Optimize method eval.

public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException {
    if (contextItem != null) {
        contextSequence = contextItem.toSequence();
    }
    boolean useCached = false;
    boolean optimize = false;
    NodeSet originalContext = null;
    if (contextSequence == null || contextSequence.isPersistentSet()) {
        // don't try to optimize in-memory node sets!
        // contextSequence will be overwritten
        originalContext = contextSequence == null ? null : contextSequence.toNodeSet();
        if (cachedContext != null && cachedContext == originalContext) {
            useCached = !originalContext.hasChanged(cachedTimestamp);
        }
        if (contextVar != null) {
            contextSequence = contextVar.eval(contextSequence);
        }
        // in the current context
        if (useCached) {
            optimize = cachedOptimize;
        } else {
            if (optimizables != null && optimizables.length > 0) {
                for (Optimizable optimizable : optimizables) {
                    if (optimizable.canOptimize(contextSequence)) {
                        optimize = true;
                    } else {
                        optimize = false;
                        break;
                    }
                }
            }
        }
    }
    if (optimize) {
        cachedContext = originalContext;
        cachedTimestamp = originalContext == null ? 0 : originalContext.getState();
        cachedOptimize = true;
        NodeSet ancestors;
        NodeSet result = null;
        for (int current = 0; current < optimizables.length; current++) {
            NodeSet selection = optimizables[current].preSelect(contextSequence, current > 0);
            if (LOG.isTraceEnabled()) {
                LOG.trace("exist:optimize: pre-selection: {}", selection.getLength());
            }
            // be re-evaluated to filter out wrong matches
            if (selection.isEmpty()) {
                ancestors = selection;
            } else if (contextStep == null || current > 0) {
                ancestors = selection.selectAncestorDescendant(contextSequence.toNodeSet(), NodeSet.ANCESTOR, true, contextId, true);
            } else {
                // NodeSelector selector;
                final long start = System.currentTimeMillis();
                // selector = new AncestorSelector(selection, contextId, true, false);
                final StructuralIndex index = context.getBroker().getStructuralIndex();
                final QName ancestorQN = contextStep.getTest().getName();
                if (optimizables[current].optimizeOnSelf()) {
                    ancestors = index.findAncestorsByTagName(ancestorQN.getNameType(), ancestorQN, Constants.SELF_AXIS, selection.getDocumentSet(), selection, contextId);
                } else {
                    ancestors = index.findAncestorsByTagName(ancestorQN.getNameType(), ancestorQN, optimizables[current].optimizeOnChild() ? Constants.PARENT_AXIS : Constants.ANCESTOR_SELF_AXIS, selection.getDocumentSet(), selection, contextId);
                }
                if (LOG.isTraceEnabled()) {
                    LOG.trace("Ancestor selection took {}", System.currentTimeMillis() - start);
                    LOG.trace("Found: {}", ancestors.getLength());
                }
            }
            result = ancestors;
            contextSequence = result;
        }
        if (contextStep == null) {
            return innerExpr.eval(result);
        } else {
            contextStep.setPreloadedData(result.getDocumentSet(), result);
            if (LOG.isTraceEnabled()) {
                LOG.trace("exist:optimize: context after optimize: {}", result.getLength());
            }
            final long start = System.currentTimeMillis();
            if (originalContext != null) {
                contextSequence = originalContext.filterDocuments(result);
            } else {
                contextSequence = null;
            }
            final Sequence seq = innerExpr.eval(contextSequence);
            if (LOG.isTraceEnabled()) {
                LOG.trace("exist:optimize: inner expr took {}; found: {}", System.currentTimeMillis() - start, seq.getItemCount());
            }
            return seq;
        }
    } else {
        if (LOG.isTraceEnabled()) {
            LOG.trace("exist:optimize: Cannot optimize expression.");
        }
        if (originalContext != null) {
            contextSequence = originalContext;
        }
        return innerExpr.eval(contextSequence, contextItem);
    }
}
Also used : NodeSet(org.exist.dom.persistent.NodeSet) StructuralIndex(org.exist.indexing.StructuralIndex) QName(org.exist.dom.QName) Sequence(org.exist.xquery.value.Sequence)

Example 49 with NodeSet

use of org.exist.dom.persistent.NodeSet in project exist by eXist-db.

the class FindLastModified method eval.

@Override
public Sequence eval(Sequence[] args, Sequence contextSequence) throws XPathException {
    final NodeSet nodes = args[0].toNodeSet();
    if (nodes.isEmpty()) {
        return Sequence.EMPTY_SEQUENCE;
    }
    final NodeSet result = new NewArrayNodeSet();
    final DateTimeValue dtv = (DateTimeValue) args[1].itemAt(0);
    final long lastModified = dtv.getDate().getTime();
    for (final NodeProxy proxy : nodes) {
        final DocumentImpl doc = proxy.getOwnerDocument();
        final long modified = doc.getLastModified();
        boolean matches;
        if (this.isCalledAs("find-last-modified-since")) {
            matches = modified > lastModified;
        } else {
            matches = modified <= lastModified;
        }
        if (matches) {
            result.add(proxy);
        }
    }
    return result;
}
Also used : NodeSet(org.exist.dom.persistent.NodeSet) NewArrayNodeSet(org.exist.dom.persistent.NewArrayNodeSet) NewArrayNodeSet(org.exist.dom.persistent.NewArrayNodeSet) DateTimeValue(org.exist.xquery.value.DateTimeValue) NodeProxy(org.exist.dom.persistent.NodeProxy) DocumentImpl(org.exist.dom.persistent.DocumentImpl)

Aggregations

NodeSet (org.exist.dom.persistent.NodeSet)49 NodeProxy (org.exist.dom.persistent.NodeProxy)18 Sequence (org.exist.xquery.value.Sequence)18 DocumentSet (org.exist.dom.persistent.DocumentSet)14 NewArrayNodeSet (org.exist.dom.persistent.NewArrayNodeSet)12 QName (org.exist.dom.QName)11 ExtArrayNodeSet (org.exist.dom.persistent.ExtArrayNodeSet)10 VirtualNodeSet (org.exist.dom.persistent.VirtualNodeSet)9 ContextItem (org.exist.dom.persistent.ContextItem)8 IOException (java.io.IOException)7 XPathException (org.exist.xquery.XPathException)7 Collator (com.ibm.icu.text.Collator)4 EXistException (org.exist.EXistException)4 DocumentImpl (org.exist.dom.persistent.DocumentImpl)4 EmptyNodeSet (org.exist.dom.persistent.EmptyNodeSet)4 Indexable (org.exist.storage.Indexable)4 SequenceIterator (org.exist.xquery.value.SequenceIterator)4 StringValue (org.exist.xquery.value.StringValue)4 NodeImpl (org.exist.dom.memtree.NodeImpl)3 Match (org.exist.dom.persistent.Match)3