private List<OIdentifiable> applyTailIndexes(final Object lastIndexResult) { final OIndex<?> beforeTheLastIndex = indexChain.get(indexChain.size() - 2); Set<Comparable> currentKeys = prepareKeys(beforeTheLastIndex, lastIndexResult); for (int j = indexChain.size() - 2; j > 0; j--) { final OIndex<?> currentIndex = indexChain.get(j); final OIndex<?> nextIndex = indexChain.get(j - 1); final Set<Comparable> newKeys; if (isComposite(currentIndex)) { newKeys = new TreeSet<Comparable>(); for (Comparable currentKey : currentKeys) { final List<OIdentifiable> currentResult = getFromCompositeIndex(currentKey, currentIndex); newKeys.addAll(prepareKeys(nextIndex, currentResult)); } } else { final OIndexCursor cursor = currentIndex.iterateEntries(currentKeys, true); final List<OIdentifiable> keys = cursorToList(cursor); newKeys = prepareKeys(nextIndex, keys); } updateStatistic(currentIndex); currentKeys = newKeys; } return applyFirstIndex(currentKeys); }
private static Collection<OIndex<?>> prepareLastIndexVariants( OClass iSchemaClass, OSQLFilterItemField.FieldChain fieldChain) { OClass oClass = iSchemaClass; final Collection<OIndex<?>> result = new ArrayList<OIndex<?>>(); for (int i = 0; i < fieldChain.getItemCount() - 1; i++) { oClass = oClass.getProperty(fieldChain.getItemName(i)).getLinkedClass(); if (oClass == null) { return result; } } final Set<OIndex<?>> involvedIndexes = new TreeSet<OIndex<?>>( new Comparator<OIndex<?>>() { public int compare(OIndex<?> o1, OIndex<?> o2) { return o1.getDefinition().getParamCount() - o2.getDefinition().getParamCount(); } }); involvedIndexes.addAll( oClass.getInvolvedIndexes(fieldChain.getItemName(fieldChain.getItemCount() - 1))); final Collection<Class<? extends OIndex>> indexTypes = new HashSet<Class<? extends OIndex>>(3); for (OIndex<?> involvedIndex : involvedIndexes) { if (!indexTypes.contains(involvedIndex.getInternal().getClass())) { result.add(involvedIndex); indexTypes.add(involvedIndex.getInternal().getClass()); } } return result; }
public List<String> getIndexNames() { final ArrayList<String> names = new ArrayList<String>(indexChain.size()); for (OIndex<?> oIndex : indexChain) { names.add(oIndex.getName()); } return names; }
/** {@inheritDoc} */ @Override public long getRebuildVersion() { long rebuildVersion = 0; for (OIndex<?> index : indexChain) { rebuildVersion += index.getRebuildVersion(); } return rebuildVersion; }
@Override public OIndexCursor iterateEntriesBetween( Object fromKey, boolean fromInclusive, Object toKey, boolean toInclusive, boolean ascOrder) { final OIndexCursor internalCursor = lastIndex.iterateEntriesBetween(fromKey, fromInclusive, toKey, toInclusive, ascOrder); return new ExternalIndexCursor(internalCursor); }
private static boolean supportNullValues(OIndex<?> index) { final ODocument metadata = index.getMetadata(); if (metadata == null) return false; final Boolean ignoreNullValues = metadata.field("ignoreNullValues"); return Boolean.FALSE.equals(ignoreNullValues); }
/** {@inheritDoc} */ @Override public T get(Object iKey) { final Object lastIndexResult = lastIndex.get(iKey); final Set<OIdentifiable> result = new HashSet<OIdentifiable>(); if (lastIndexResult != null) result.addAll(applyTailIndexes(lastIndexResult)); return (T) result; }
/** * Make type conversion of keys for specific index. * * @param index - index for which keys prepared for. * @param keys - which should be prepared. * @return keys converted to necessary type. */ private Set<Comparable> prepareKeys(OIndex<?> index, Object keys) { final OIndexDefinition indexDefinition = index.getDefinition(); if (keys instanceof Collection) { final Set<Comparable> newKeys = new TreeSet<Comparable>(); for (Object o : ((Collection) keys)) { newKeys.add((Comparable) indexDefinition.createValue(o)); } return newKeys; } else { return Collections.singleton((Comparable) indexDefinition.createValue(keys)); } }
/** * Register statistic information about usage of index in {@link OProfilerStub}. * * @param index which usage is registering. */ private void updateStatistic(OIndex<?> index) { final OProfiler profiler = Orient.instance().getProfiler(); if (profiler.isRecording()) { Orient.instance() .getProfiler() .updateCounter( profiler.getDatabaseMetric(index.getDatabaseName(), "query.indexUsed"), "Used index in query", +1); final int paramCount = index.getDefinition().getParamCount(); if (paramCount > 1) { final String profiler_prefix = profiler.getDatabaseMetric(index.getDatabaseName(), "query.compositeIndexUsed"); profiler.updateCounter(profiler_prefix, "Used composite index in query", +1); profiler.updateCounter( profiler_prefix + "." + paramCount, "Used composite index in query with " + paramCount + " params", +1); } } }
private List<OIdentifiable> applyFirstIndex(Collection<Comparable> currentKeys) { final List<OIdentifiable> result; if (isComposite(firstIndex)) { result = new ArrayList<OIdentifiable>(); for (Comparable key : currentKeys) { result.addAll(getFromCompositeIndex(key, firstIndex)); } } else { final OIndexCursor cursor = firstIndex.iterateEntries(currentKeys, true); result = cursorToList(cursor); } updateStatistic(firstIndex); return result; }
private static int priorityOfUsage(OIndex<?> index) { if (index == null) return -1; final OClass.INDEX_TYPE indexType = OClass.INDEX_TYPE.valueOf(index.getType()); final boolean isComposite = isComposite(index); final boolean supportNullValues = supportNullValues(index); int priority = 1; if (isComposite) { if (!supportNullValues) return -1; } else { priority += 10; } switch (indexType) { case UNIQUE_HASH_INDEX: case NOTUNIQUE_HASH_INDEX: if (isComposite) return -1; else priority += 10; break; case UNIQUE: case NOTUNIQUE: priority += 5; break; case PROXY: case FULLTEXT: case DICTIONARY: case FULLTEXT_HASH_INDEX: case DICTIONARY_HASH_INDEX: case SPATIAL: return -1; } return priority; }
private static boolean isComposite(OIndex<?> currentIndex) { return currentIndex.getDefinition().getParamCount() > 1; }
@Override public OIndexCursor iterateEntriesMinor(Object toKey, boolean toInclusive, boolean ascOrder) { final OIndexCursor internalCursor = lastIndex.iterateEntriesMinor(toKey, toInclusive, ascOrder); return new ExternalIndexCursor(internalCursor); }
public String getDatabaseName() { return firstIndex.getDatabaseName(); }
@Override public OIndexCursor iterateEntries(Collection<?> keys, boolean ascSortOrder) { final OIndexCursor internalCursor = lastIndex.iterateEntries(keys, ascSortOrder); return new ExternalIndexCursor(internalCursor); }
@Override public boolean isUnique() { return firstIndex.isUnique(); }
public ODocument checkEntry(final OIdentifiable iRecord, final Object iKey) { return firstIndex.checkEntry(iRecord, iKey); }
/** * Returns internal index of last chain index, because proxy applicable to all operations that * last index applicable. */ public OIndexInternal<T> getInternal() { return (OIndexInternal<T>) lastIndex.getInternal(); }
/** {@inheritDoc} */ public OIndexDefinition getDefinition() { return lastIndex.getDefinition(); }
private List<OIdentifiable> getFromCompositeIndex(Comparable currentKey, OIndex<?> currentIndex) { final OIndexCursor cursor = currentIndex.iterateEntriesBetween(currentKey, true, currentKey, true, true); return cursorToList(cursor); }