diff --git a/.idea/cqengine.iml b/.idea/cqengine.iml new file mode 100644 index 000000000..d6ebd4805 --- /dev/null +++ b/.idea/cqengine.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 000000000..07c77b990 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 000000000..797acea53 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 000000000..98b527bf0 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 000000000..16814f098 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1660071714697 + + + + + + + + + \ No newline at end of file diff --git a/code/.gitignore b/code/.gitignore new file mode 100644 index 000000000..8c34b7358 --- /dev/null +++ b/code/.gitignore @@ -0,0 +1,56 @@ +### +# Eclipse +### +.classpath +.cproject +.project +.settings +/bin/ + +### +# IntelliJ +### +*.iml +.idea +.attach* +### +# Maven +### +target/ +target.*/ + +### +# Maven shade plugin +### +*dependency-reduced-pom.xml + +### +# Build artifacts +### +*.class +*.o +*.so +*.jar + + +### +# vi(m) temp files +### +*.swp +*.swo +*.swn + +### +# Visual Studio +### +.vscode/ + +### +# Misc files +### +org.kde.konsole.desktop + +### +# Open API generated files +#### +*.openapi-generator diff --git a/code/README b/code/README new file mode 100644 index 000000000..e69de29bb diff --git a/code/pom.xml b/code/pom.xml index d8b4c50f5..a1a88ccf2 100644 --- a/code/pom.xml +++ b/code/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.googlecode.cqengine cqengine - 3.5.0 + 3.5.0-OPENET-SNAPSHOT jar CQEngine Collection Query Engine: NoSQL indexing and query engine for Java collections with ultra-low latency @@ -23,7 +23,7 @@ https://github.com/npgall/${project.artifactId}.git scm:git:https://github.com/npgall/${project.artifactId}.git scm:git:git@github.com:npgall/${project.artifactId}.git - 3.5.0 + 3.5.0-OPENET @@ -116,16 +116,13 @@ org.apache.maven.plugins @@ -246,6 +243,24 @@ 3.25.0-GA + + org.projectlombok + lombok + 1.18.8 + provided + + + + org.slf4j + slf4j-api + 1.7.26 + + + org.slf4j + slf4j-simple + 1.7.26 + + org.xerial sqlite-jdbc @@ -337,10 +352,8 @@ org.apache.maven.plugins @@ -360,9 +373,7 @@ com.mycila.maven-license-plugin @@ -426,4 +437,4 @@ - + \ No newline at end of file diff --git a/code/src/main/java/com/googlecode/cqengine/ConcurrentIndexedCollection.java b/code/src/main/java/com/googlecode/cqengine/ConcurrentIndexedCollection.java index 7585cbc7c..095d638e9 100644 --- a/code/src/main/java/com/googlecode/cqengine/ConcurrentIndexedCollection.java +++ b/code/src/main/java/com/googlecode/cqengine/ConcurrentIndexedCollection.java @@ -18,6 +18,8 @@ import com.googlecode.cqengine.engine.QueryEngineInternal; import com.googlecode.cqengine.engine.CollectionQueryEngine; import com.googlecode.cqengine.index.Index; +import com.googlecode.cqengine.index.indexOrdering.ConcurrentInvertedRadixTreesHolder; +import com.googlecode.cqengine.index.indexOrdering.IConcurrentInvertedRadixTreesHolder; import com.googlecode.cqengine.index.support.CloseableIterator; import com.googlecode.cqengine.index.support.CloseableRequestResources; import com.googlecode.cqengine.metadata.MetadataEngine; @@ -35,6 +37,7 @@ import java.util.*; +import static com.googlecode.cqengine.query.QueryFactory.in; import static com.googlecode.cqengine.query.QueryFactory.queryOptions; import static java.util.Collections.singleton; @@ -70,6 +73,7 @@ public class ConcurrentIndexedCollection implements IndexedCollection { protected final ObjectStore objectStore; protected final QueryEngineInternal indexEngine; protected final MetadataEngine metadataEngine; + protected IConcurrentInvertedRadixTreesHolder indexOrderingConcurrentTreeHolder; /** * Creates a new {@link ConcurrentIndexedCollection} with default settings, using {@link OnHeapPersistence}. @@ -135,6 +139,7 @@ public ResultSet retrieve(Query query) { public ResultSet retrieve(Query query, QueryOptions queryOptions) { final QueryOptions finalQueryOptions = openRequestScopeResourcesIfNecessary(queryOptions); flagAsReadRequest(finalQueryOptions); + indexEngine.setConcurrentInvertedRadixTree(getConcurrentInvertedRadixTree()); ResultSet results = indexEngine.retrieve(query, finalQueryOptions); return new CloseableResultSet(results, query, finalQueryOptions) { @Override @@ -577,4 +582,16 @@ public String toString() { protected static void flagAsReadRequest(QueryOptions queryOptions) { FlagsEnabled.forQueryOptions(queryOptions).add(PersistenceFlags.READ_REQUEST); } + + + @Override + public void setConcurrentInvertedRadixTree(IConcurrentInvertedRadixTreesHolder singletonConcurrentTreeHolder) { + this.indexOrderingConcurrentTreeHolder = singletonConcurrentTreeHolder; + } + + + @Override + public IConcurrentInvertedRadixTreesHolder getConcurrentInvertedRadixTree() { + return this.indexOrderingConcurrentTreeHolder; + } } diff --git a/code/src/main/java/com/googlecode/cqengine/IndexedCollection.java b/code/src/main/java/com/googlecode/cqengine/IndexedCollection.java index 8807fe81a..5f4db90a9 100644 --- a/code/src/main/java/com/googlecode/cqengine/IndexedCollection.java +++ b/code/src/main/java/com/googlecode/cqengine/IndexedCollection.java @@ -17,6 +17,8 @@ import com.googlecode.cqengine.engine.QueryEngine; import com.googlecode.cqengine.index.Index; +import com.googlecode.cqengine.index.indexOrdering.ConcurrentInvertedRadixTreesHolder; +import com.googlecode.cqengine.index.indexOrdering.IConcurrentInvertedRadixTreesHolder; import com.googlecode.cqengine.metadata.MetadataEngine; import com.googlecode.cqengine.persistence.Persistence; import com.googlecode.cqengine.query.Query; @@ -157,4 +159,14 @@ public interface IndexedCollection extends Set, QueryEngine { * on the distribution of attribute values in the collection. */ MetadataEngine getMetadataEngine(); + + + + void setConcurrentInvertedRadixTree(IConcurrentInvertedRadixTreesHolder singletonConcurrentTreeHolder); + + + + IConcurrentInvertedRadixTreesHolder getConcurrentInvertedRadixTree(); + + // get concurrent radix tree } diff --git a/code/src/main/java/com/googlecode/cqengine/engine/CollectionQueryEngine.java b/code/src/main/java/com/googlecode/cqengine/engine/CollectionQueryEngine.java index a0cdf7bcf..5754ae489 100644 --- a/code/src/main/java/com/googlecode/cqengine/engine/CollectionQueryEngine.java +++ b/code/src/main/java/com/googlecode/cqengine/engine/CollectionQueryEngine.java @@ -1,12 +1,12 @@ /** * Copyright 2012-2015 Niall Gallagher - * + *

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,9 +16,11 @@ package com.googlecode.cqengine.engine; import com.googlecode.concurrenttrees.common.LazyIterator; +import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree; import com.googlecode.cqengine.attribute.*; import com.googlecode.cqengine.index.AttributeIndex; import com.googlecode.cqengine.index.Index; +import com.googlecode.cqengine.index.indexOrdering.IConcurrentInvertedRadixTreesHolder; import com.googlecode.cqengine.index.sqlite.IdentityAttributeIndex; import com.googlecode.cqengine.index.sqlite.SQLiteIdentityIndex; import com.googlecode.cqengine.index.sqlite.SimplifiedSQLiteIndex; @@ -60,10 +62,16 @@ import com.googlecode.cqengine.resultset.order.MaterializedDeduplicatedResultSet; import com.googlecode.cqengine.resultset.order.MaterializedOrderedResultSet; import com.googlecode.cqengine.index.support.CloseableRequestResources.CloseableResourceGroup; +import lombok.extern.slf4j.Slf4j; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; import static com.googlecode.cqengine.query.QueryFactory.*; import static com.googlecode.cqengine.query.option.EngineFlags.INDEX_ORDERING_ALLOW_FAST_ORDERING_OF_MULTI_VALUED_ATTRIBUTES; @@ -78,6 +86,7 @@ * * @author Niall Gallagher */ +@Slf4j public class CollectionQueryEngine implements QueryEngineInternal { // A key used to store the root query in the QueryOptions, so it may be accessed by partial indexes... @@ -97,6 +106,7 @@ public class CollectionQueryEngine implements QueryEngineInternal { private final FallbackIndex fallbackIndex = new FallbackIndex(); // Updated as indexes are added or removed, this is used by the isMutable() method... private final Set> immutableIndexes = Collections.newSetFromMap(new ConcurrentHashMap<>()); + private IConcurrentInvertedRadixTreesHolder indexOrderingConcurrentRadixTreeHolder; public CollectionQueryEngine() { } @@ -110,7 +120,7 @@ public void init(final ObjectStore objectStore, final QueryOptions queryOptio if (objectStore instanceof SQLiteObjectStore) { // If the collection is backed by a SQLiteObjectStore, add the backing index of the SQLiteObjectStore // so that it can also be used as a regular index to accelerate queries... - SQLiteObjectStore> sqLiteObjectStore = (SQLiteObjectStore>)objectStore; + SQLiteObjectStore> sqLiteObjectStore = (SQLiteObjectStore>) objectStore; SQLiteIdentityIndex, O> backingIndex = sqLiteObjectStore.getBackingIndex(); addIndex(backingIndex, queryOptions); } @@ -129,6 +139,7 @@ public boolean perform(Index index) { /** * This is a no-op here, as currently the {@link ModificationListener#destroy(QueryOptions)} method * is only used by indexes. + * * @param queryOptions Optional parameters for the update */ @Override @@ -147,14 +158,12 @@ public void addIndex(Index index, QueryOptions queryOptions) { @SuppressWarnings({"unchecked"}) StandingQueryIndex standingQueryIndex = (StandingQueryIndex) index; addStandingQueryIndex(standingQueryIndex, standingQueryIndex.getStandingQuery(), queryOptions); - } - else if (index instanceof CompoundIndex) { + } else if (index instanceof CompoundIndex) { @SuppressWarnings({"unchecked"}) CompoundIndex compoundIndex = (CompoundIndex) index; CompoundAttribute compoundAttribute = compoundIndex.getAttribute(); addCompoundIndex(compoundIndex, compoundAttribute, queryOptions); - } - else if (index instanceof AttributeIndex) { + } else if (index instanceof AttributeIndex) { @SuppressWarnings({"unchecked"}) AttributeIndex attributeIndex = (AttributeIndex) index; Attribute indexedAttribute = attributeIndex.getAttribute(); @@ -163,12 +172,10 @@ else if (index instanceof AttributeIndex) { StandingQueryAttribute standingQueryAttribute = (StandingQueryAttribute) indexedAttribute; Query standingQuery = standingQueryAttribute.getQuery(); addStandingQueryIndex(index, standingQuery, queryOptions); - } - else { + } else { addAttributeIndex(attributeIndex, queryOptions); } - } - else { + } else { throw new IllegalStateException("Unexpected type of index: " + (index == null ? null : index.getClass().getName())); } if (!index.isMutable()) { @@ -178,8 +185,9 @@ else if (index instanceof AttributeIndex) { /** * Adds an {@link AttributeIndex}. + * * @param attributeIndex The index to add - * @param The type of objects indexed + * @param The type of objects indexed */ void addAttributeIndex(AttributeIndex attributeIndex, QueryOptions queryOptions) { Attribute attribute = attributeIndex.getAttribute(); @@ -210,11 +218,11 @@ void addAttributeIndex(AttributeIndex attributeIndex, QueryOptions que } - /** * Adds either a {@link StandingQueryIndex} or a regular index build on a {@link StandingQueryAttribute}. + * * @param standingQueryIndex The index to add - * @param standingQuery The query on which the index is based + * @param standingQuery The query on which the index is based */ void addStandingQueryIndex(Index standingQueryIndex, Query standingQuery, QueryOptions queryOptions) { Index existingIndex = standingQueryIndexes.putIfAbsent(standingQuery, standingQueryIndex); @@ -228,7 +236,8 @@ void addStandingQueryIndex(Index standingQueryIndex, Query standingQuery, /** * Adds a {@link CompoundIndex}. - * @param compoundIndex The index to add + * + * @param compoundIndex The index to add * @param compoundAttribute The compound attribute on which the index is based */ void addCompoundIndex(CompoundIndex compoundIndex, CompoundAttribute compoundAttribute, QueryOptions queryOptions) { @@ -254,15 +263,13 @@ public void removeIndex(Index index, QueryOptions queryOptions) { StandingQueryIndex standingQueryIndex = (StandingQueryIndex) index; removed = standingQueryIndexes.remove(standingQueryIndex.getStandingQuery(), standingQueryIndex); - } - else if (index instanceof CompoundIndex) { + } else if (index instanceof CompoundIndex) { @SuppressWarnings({"unchecked"}) CompoundIndex compoundIndex = (CompoundIndex) index; CompoundAttribute compoundAttribute = compoundIndex.getAttribute(); removed = compoundIndexes.remove(compoundAttribute, compoundIndex); - } - else if (index instanceof AttributeIndex) { + } else if (index instanceof AttributeIndex) { @SuppressWarnings({"unchecked"}) AttributeIndex attributeIndex = (AttributeIndex) index; Attribute indexedAttribute = attributeIndex.getAttribute(); @@ -273,8 +280,7 @@ else if (index instanceof AttributeIndex) { Query standingQuery = standingQueryAttribute.getQuery(); removed = standingQueryIndexes.remove(standingQuery, index); - } - else { + } else { Set> indexesOnThisAttribute = attributeIndexes.get(indexedAttribute); removed = indexesOnThisAttribute.remove(attributeIndex); @@ -290,8 +296,7 @@ else if (index instanceof AttributeIndex) { attributeIndexes.remove(indexedAttribute); } } - } - else { + } else { throw new IllegalStateException("Unexpected type of index: " + (index == null ? null : index.getClass().getName())); } if (removed && !index.isMutable()) { @@ -320,6 +325,11 @@ public Iterable> getIndexes() { return indexes; } + @Override + public void setConcurrentInvertedRadixTree(IConcurrentInvertedRadixTreesHolder singletonConcurrentTreeHolder) { + this.indexOrderingConcurrentRadixTreeHolder = singletonConcurrentTreeHolder; + } + /** * Returns an {@link Iterable} over all indexes which have been added on the given attribute, including the * {@link FallbackIndex} which is implicitly available on all attributes. @@ -373,7 +383,7 @@ public QueryOptions getQueryOptions() { *

* For a definition of retrieval cost see {@link ResultSet#getRetrievalCost()}. * - * @param query The query which refers to an attribute + * @param query The query which refers to an attribute * @param queryOptions Optional parameters for the query * @return A {@link ResultSet} from the index with the lowest retrieval cost which supports the given query */ @@ -390,7 +400,7 @@ ResultSet retrieveSimpleQuery(SimpleQuery query, QueryOptions query // Check if a UniqueIndex is available, as this will have the lowest cost of attribute-based indexes... Index uniqueIndex = uniqueIndexes.get(query.getAttribute()); - if (uniqueIndex!= null && uniqueIndex.supportsQuery(query, queryOptions)){ + if (uniqueIndex != null && uniqueIndex.supportsQuery(query, queryOptions)) { return uniqueIndex.retrieve(query, queryOptions); } @@ -426,7 +436,7 @@ ResultSet retrieveSimpleQuery(SimpleQuery query, QueryOptions query *

* For a definition of retrieval cost see {@link ResultSet#getRetrievalCost()}. * - * @param query The query which refers to an attribute + * @param query The query which refers to an attribute * @param queryOptions Optional parameters for the query * @return A {@link ResultSet} from the index with the lowest retrieval cost which supports the given query */ @@ -492,10 +502,10 @@ public ResultSet retrieve(final Query query, final QueryOptions queryOptio // Check if an index is actually available to support it... AttributeOrder firstOrder = allSortOrders.iterator().next(); @SuppressWarnings("unchecked") - Attribute firstAttribute = (Attribute)firstOrder.getAttribute(); + Attribute firstAttribute = (Attribute) firstOrder.getAttribute(); if (firstAttribute instanceof OrderControlAttribute) { @SuppressWarnings("unchecked") - Attribute firstAttributeDelegate = ((OrderControlAttribute)firstAttribute).getDelegateAttribute(); + Attribute firstAttributeDelegate = ((OrderControlAttribute) firstAttribute).getDelegateAttribute(); firstAttribute = firstAttributeDelegate; } @@ -519,7 +529,7 @@ public ResultSet retrieve(final Query query, final QueryOptions queryOptio // efficiently. Now check if an index exists which would allow index ordering... for (Index index : this.getIndexesOnAttribute(firstAttribute)) { if (index instanceof SortedKeyStatisticsAttributeIndex && !index.isQuantized()) { - indexForOrdering = (SortedKeyStatisticsAttributeIndex)index; + indexForOrdering = (SortedKeyStatisticsAttributeIndex) index; break; } } @@ -538,15 +548,13 @@ public ResultSet retrieve(final Query query, final QueryOptions queryOptio // Index ordering has been requested explicitly. // Don't bother calculating query selectivity, assign low selectivity so we will use the index... querySelectivity = 0.0; - } - else if (!indexForOrdering.supportsQuery(has(firstAttribute), queryOptions)) { + } else if (!indexForOrdering.supportsQuery(has(firstAttribute), queryOptions)) { // Index ordering was not requested explicitly, and we cannot calculate the selectivity. // In this case even though we have an index which supports index ordering, // we don't have enough information to say that it would be beneficial. // Assign high selectivity so that the materialize strategy will be used instead... querySelectivity = 1.0; - } - else { + } else { // The index supports has() queries, which allows us to calculate selectivity. // Calculate query selectivity, based on the query cardinality and index cardinality... final int queryCardinality = retrieveRecursive(query, queryOptions).getMergeCost(); @@ -558,13 +566,11 @@ else if (!indexForOrdering.supportsQuery(has(firstAttribute), queryOptions)) { if (indexCardinality == 0) { // Handle edge case where the index is empty. querySelectivity = 1.0; // treat is as if the query has high selectivity (tend to use materialize). - } - else if (queryCardinality > indexCardinality) { + } else if (queryCardinality > indexCardinality) { // Handle edge case where query cardinality is greater than index cardinality. querySelectivity = 0.0; // treat is as if the query has low selectivity (tend to use index ordering). - } - else { - querySelectivity = 1.0 - queryCardinality / (double)indexCardinality; + } else { + querySelectivity = 1.0 - queryCardinality / (double) indexCardinality; } } @@ -584,12 +590,14 @@ else if (queryCardinality > indexCardinality) { ResultSet resultSet; if (indexForOrdering != null) { // Retrieve results, using an index to accelerate ordering... - resultSet = retrieveWithIndexOrdering(query, queryOptions, orderByOption, indexForOrdering); + Query queryToManipulate = query; + queryToManipulate = handleConcurrentRadixTree(queryToManipulate, queryOptions, orderByOption, indexForOrdering); + resultSet = retrieveWithIndexOrdering(queryToManipulate, queryOptions, orderByOption, indexForOrdering); + resultSet = filterResultBaseOnLongest(queryToManipulate,queryOptions,resultSet); if (queryLog != null) { queryLog.log("orderingStrategy: index"); } - } - else { + } else { // Retrieve results, without using an index to accelerate ordering... resultSet = retrieveWithoutIndexOrdering(query, queryOptions, orderByOption); if (queryLog != null) { @@ -608,6 +616,229 @@ public void close() { }; } + private ResultSet filterResultBaseOnLongest(Query query, QueryOptions queryOptions, ResultSet resultSet) { + + List result = new ArrayList<>(); + try { + + List elements = resultSet.stream().collect(Collectors.toList()); + + Map maxLengthPerAttributeMap = new HashMap<>(); + + + List> longestPrefixAttrs = (List>) AttrObjectOptions.getAttrObjectOption(queryOptions, ConcurrentRadixTreeLongestPrefixMatch.CONCURRENT_RADIX_TREE_LONGEST_PREFIX_MATCH_BY_ATTRIBUTES); + + if(longestPrefixAttrs== null || longestPrefixAttrs.isEmpty()){ + return resultSet; + } + + + if(!elements.isEmpty()){ + + handleFirstRecordLongest(result, elements, maxLengthPerAttributeMap, longestPrefixAttrs); + + handlemostlongestrecords(result, elements, maxLengthPerAttributeMap, longestPrefixAttrs); + + + } + + + + }catch (NoSuchFieldException noSuchFieldException){ + log.error(noSuchFieldException.getMessage()); + } + + return new ResultSet() { + @Override + public Iterator iterator() { + return result.iterator(); + } + + @Override + public boolean contains(O object) { + ResultSet rs = retrieveWithoutIndexOrdering(query, queryOptions, null); + try { + return rs.contains(object); + } finally { + rs.close(); + } + } + + @Override + public boolean matches(O object) { + return query.matches(object, queryOptions); + } + + @Override + public Query getQuery() { + return query; + } + + @Override + public QueryOptions getQueryOptions() { + return queryOptions; + } + + @Override + public int getRetrievalCost() { + ResultSet rs = retrieveWithoutIndexOrdering(query, queryOptions, null); + try { + return rs.getRetrievalCost(); + } finally { + rs.close(); + } + } + + @Override + public int getMergeCost() { + ResultSet rs = retrieveWithoutIndexOrdering(query, queryOptions, null); + try { + return rs.getMergeCost(); + } finally { + rs.close(); + } + } + + @Override + public int size() { + ResultSet rs = retrieveWithoutIndexOrdering(query, queryOptions, null); + try { + return rs.size(); + } finally { + rs.close(); + } + } + + @Override + public void close() { + + } + }; + + + + } + + private void handleFirstRecordLongest(List result, List elements, Map maxLengthPerAttributeMap, List> longestPrefixAttrs) throws NoSuchFieldException { + result.add(elements.get(0)); + for(Attribute attribute: longestPrefixAttrs) { + + char c[] = attribute.getAttributeName().toCharArray(); + c[0] = Character.toLowerCase(c[0]); + String attributeName = new String(c); + Field field = result.get(0).getClass().getDeclaredField(attributeName); + + String value = (String)runGetter(field, result.get(0)); + + maxLengthPerAttributeMap.put(attribute.getAttributeName(), value.length()); + + } + } + + private void handlemostlongestrecords(List result, List elements, Map maxLengthPerAttributeMap, List> longestPrefixAttrs) throws NoSuchFieldException { + for(O element : elements) { + + if(element== result.get(0)){ + continue; + } + boolean isRecordContainsLongest = true; + for(Attribute attribute: longestPrefixAttrs) { + + char c[] = attribute.getAttributeName().toCharArray(); + c[0] = Character.toLowerCase(c[0]); + String attributeName = new String(c); + Field field = element.getClass().getDeclaredField(attributeName); + + String value = (String)runGetter(field, element); + + Integer maxLength = maxLengthPerAttributeMap.get(attribute.getAttributeName()); + + if(maxLength > value.length()) { + isRecordContainsLongest =false; + break; + } + + System.out.println(value); + + } + + if(isRecordContainsLongest) { + result.add(element); + }else{ + break; + } + + + } + } + + + public Object runGetter(Field field, O o) + { + // MZ: Find the correct method + for (Method method : o.getClass().getDeclaredMethods()) + { + if ((method.getName().startsWith("get")) && (method.getName().length() == (field.getName().length() + 3))) + { + if (method.getName().toLowerCase().endsWith(field.getName().toLowerCase())) + { + // MZ: Method found, run it + try + { + return method.invoke(o); + } + catch (IllegalAccessException e) + { + log.error("Could not determine method: " + method.getName()); + } + catch (InvocationTargetException e) + { + log.error("Could not determine method: " + method.getName()); + } + + } + } + } + + + return null; + } + + private Query handleConcurrentRadixTree(Query query, QueryOptions queryOptions, OrderByOption orderByOption, SortedKeyStatisticsAttributeIndex indexForOrdering) { + + Query finalQuery = query; + + + List> longestPrefixAttrs = (List>) AttrObjectOptions.getAttrObjectOption(queryOptions, ConcurrentRadixTreeLongestPrefixMatch.CONCURRENT_RADIX_TREE_LONGEST_PREFIX_MATCH_BY_ATTRIBUTES); + + + List longestPrefixValues = (List) AttrObjectOptions.getAttrObjectOption(queryOptions, ConcurrentRadixTreeLongestPrefixMatch.CONCURRENT_RADIX_TREE_LONGEST_PREFIX_MATCH_BY_VALUES); + + if(longestPrefixAttrs==null || longestPrefixAttrs.isEmpty()){ + return finalQuery; + } + + int index = 0; + for (Attribute attr : longestPrefixAttrs) { + + ConcurrentInvertedRadixTree concurrentInvertedRadixTree = indexOrderingConcurrentRadixTreeHolder.getConcurrentInvertedRadixTree(attr.getAttributeName()).getConcurrentInvertedRadixTree(); + Iterable keysPrefixing = concurrentInvertedRadixTree.getKeysPrefixing(longestPrefixValues.get(index)); + List prefixingList = new ArrayList<>(); + for (String element : keysPrefixing) { + prefixingList.add(element); + } + log.info("KeyPrefixing after filtering: " + prefixingList); + Query in = in(longestPrefixAttrs.get(index), prefixingList); + finalQuery = and(in, finalQuery); + index++; + + + } + return finalQuery; + // i need to get the fields name from the results to identify where is the values that i need to work with. + + } + /** * Retrieve results and then sort them afterwards (if sorting is required). */ @@ -626,8 +857,7 @@ ResultSet retrieveWithoutIndexOrdering(Query query, QueryOptions queryOpti // requested both ordering AND deduplication explicitly (hence we pass applyMaterializeDeduplication)... Comparator comparator = new AttributeOrdersComparator(orderByOption.getAttributeOrders(), queryOptions); resultSet = new MaterializedOrderedResultSet(resultSet, comparator, applyMaterializedDeduplication); - } - else if (applyMaterializedDeduplication) { + } else if (applyMaterializedDeduplication) { // A DeduplicationOption was specified, wrap the results in an MaterializedDeduplicatedResultSet, // which will deduplicate (but not sort) results. O(n) time complexity to subsequently iterate... resultSet = new MaterializedDeduplicatedResultSet(resultSet); @@ -646,14 +876,12 @@ ResultSet retrieveWithIndexOrdering(final Query query, final QueryOptions // If the client wrapped the first attribute by which results should be ordered in an OrderControlAttribute, // assign it here... - @SuppressWarnings("unchecked") - final OrderControlAttribute orderControlAttribute = + @SuppressWarnings("unchecked") final OrderControlAttribute orderControlAttribute = (primarySortOrder.getAttribute() instanceof OrderControlAttribute) - ? (OrderControlAttribute)primarySortOrder.getAttribute() : null; + ? (OrderControlAttribute) primarySortOrder.getAttribute() : null; // If the first attribute by which results should be ordered was wrapped, unwrap it, and assign it here... - @SuppressWarnings("unchecked") - final Attribute primarySortAttribute = + @SuppressWarnings("unchecked") final Attribute primarySortAttribute = (orderControlAttribute == null) ? (Attribute) primarySortOrder.getAttribute() : (Attribute) orderControlAttribute.getDelegateAttribute(); @@ -663,8 +891,7 @@ ResultSet retrieveWithIndexOrdering(final Query query, final QueryOptions final boolean attributeCanHaveZeroValues = !(primarySortAttribute instanceof SimpleAttribute); final boolean attributeCanHaveMoreThanOneValue = !(primarySortAttribute instanceof SimpleAttribute || primarySortAttribute instanceof SimpleNullableAttribute); - @SuppressWarnings("unchecked") - final RangeBounds rangeBoundsFromQuery = getBoundsFromQuery(query, primarySortAttribute); + @SuppressWarnings("unchecked") final RangeBounds rangeBoundsFromQuery = getBoundsFromQuery(query, primarySortAttribute); return new ResultSet() { @Override @@ -681,18 +908,14 @@ public Iterator iterator() { // Concatenate the main results and the missing objects, accounting for which batch should come first... if (orderControlAttribute instanceof OrderMissingFirstAttribute) { combinedResults = ConcatenatingIterator.concatenate(Arrays.asList(missingResults, mainResults)); - } - else if (orderControlAttribute instanceof OrderMissingLastAttribute) { + } else if (orderControlAttribute instanceof OrderMissingLastAttribute) { combinedResults = ConcatenatingIterator.concatenate(Arrays.asList(mainResults, missingResults)); - } - else if (primarySortOrder.isDescending()) { + } else if (primarySortOrder.isDescending()) { combinedResults = ConcatenatingIterator.concatenate(Arrays.asList(mainResults, missingResults)); - } - else { + } else { combinedResults = ConcatenatingIterator.concatenate(Arrays.asList(missingResults, mainResults)); } - } - else { + } else { combinedResults = mainResults; } @@ -701,6 +924,7 @@ else if (primarySortOrder.isDescending()) { // and so otherwise could be returned more than once... combinedResults = new MaterializedDeduplicatedIterator(combinedResults); } + return combinedResults; } @@ -709,8 +933,7 @@ public boolean contains(O object) { ResultSet rs = retrieveWithoutIndexOrdering(query, queryOptions, null); try { return rs.contains(object); - } - finally { + } finally { rs.close(); } } @@ -735,8 +958,7 @@ public int getRetrievalCost() { ResultSet rs = retrieveWithoutIndexOrdering(query, queryOptions, null); try { return rs.getRetrievalCost(); - } - finally { + } finally { rs.close(); } } @@ -746,8 +968,7 @@ public int getMergeCost() { ResultSet rs = retrieveWithoutIndexOrdering(query, queryOptions, null); try { return rs.getMergeCost(); - } - finally { + } finally { rs.close(); } } @@ -757,8 +978,7 @@ public int size() { ResultSet rs = retrieveWithoutIndexOrdering(query, queryOptions, null); try { return rs.size(); - } - finally { + } finally { rs.close(); } } @@ -768,6 +988,8 @@ public void close() { } }; + + /// } Iterator retrieveWithIndexOrderingMainResults(final Query query, QueryOptions queryOptions, SortedKeyStatisticsIndex indexForOrdering, List> allSortOrders, RangeBounds rangeBoundsFromQuery, boolean attributeCanHaveMoreThanOneValue, boolean primarySortDescending) { @@ -789,8 +1011,7 @@ protected O computeNext() { return keysAndValuesInRange.hasNext() ? keysAndValuesInRange.next().getValue() : endOfData(); } }; - } - else { + } else { sorted = concatenate(groupAndSort(keysAndValuesInRange, new AttributeOrdersComparator(sortOrdersForBucket, queryOptions))); } @@ -832,8 +1053,8 @@ Iterator retrieveWithIndexOrderingMissingResults(final Query query, QueryO * This method will add any resources which need to be closed to {@link CloseableRequestResources} in the query options. * * @param sortedCandidateResults The candidate results to be filtered - * @param query The query - * @param queryOptions The query options + * @param query The query + * @param queryOptions The query options * @return A filtered iterator which returns the subset of candidate objects which match the query */ Iterator filterIndexOrderingCandidateResults(final Iterator sortedCandidateResults, final Query query, final QueryOptions queryOptions) { @@ -844,8 +1065,7 @@ Iterator filterIndexOrderingCandidateResults(final Iterator sortedCandidat // No index is available to accelerate the index merge strategy... indexAcceleratedQueryResults.close(); // We fall back to filtering via query.matches() below. - } - else { + } else { // Ensure that indexAcceleratedQueryResults is closed at the end of processing the request... final CloseableResourceGroup closeableResourceGroup = CloseableRequestResources.forQueryOptions(queryOptions).addGroup(); closeableResourceGroup.add(indexAcceleratedQueryResults); @@ -882,7 +1102,7 @@ static > Persistence getPersistenceFromQueryOpt * Called when using an index to order results, to determine if or how results within each bucket * in that index should be sorted. *

- * + *

* We must sort results within each bucket, when: *

    *
  1. @@ -899,9 +1119,9 @@ static > Persistence getPersistenceFromQueryOpt *
  2. *
* - * @param allSortOrders The user-specified sort orders + * @param allSortOrders The user-specified sort orders * @param attributeCanHaveMoreThanOneValue If the primary attribute used for sorting can return more than one value - * @param index The index from which the bucket is accessed + * @param index The index from which the bucket is accessed * @return A list of AttributeOrder objects representing the sort order to apply to objects in the bucket */ static List> determineAdditionalSortOrdersForIndexOrdering(List> allSortOrders, boolean attributeCanHaveMoreThanOneValue, Index index, QueryOptions queryOptions) { @@ -919,8 +1139,7 @@ static , O> CloseableIterator> getKeysAnd typedBounds.upperBound, typedBounds.upperInclusive, queryOptions ).iterator(); - } - else { + } else { return index.getKeysAndValuesDescending( typedBounds.lowerBound, typedBounds.lowerInclusive, typedBounds.upperBound, typedBounds.upperInclusive, @@ -949,9 +1168,8 @@ static , O> RangeBounds getBoundsFromQuery(Query quer List> candidateRangeQueries = Collections.emptyList(); if (query instanceof SimpleQuery) { candidateRangeQueries = Collections.>singletonList((SimpleQuery) query); - } - else if (query instanceof And) { - And and = (And)query; + } else if (query instanceof And) { + And and = (And) query; if (and.hasSimpleQueries()) { candidateRangeQueries = and.getSimpleQueries(); } @@ -963,14 +1181,12 @@ else if (query instanceof And) { GreaterThan bound = (GreaterThan) candidate; lowerBound = bound.getValue(); lowerInclusive = bound.isValueInclusive(); - } - else if (candidate instanceof LessThan) { + } else if (candidate instanceof LessThan) { @SuppressWarnings("unchecked") LessThan bound = (LessThan) candidate; upperBound = bound.getValue(); upperInclusive = bound.isValueInclusive(); - } - else if (candidate instanceof Between) { + } else if (candidate instanceof Between) { @SuppressWarnings("unchecked") Between bound = (Between) candidate; lowerBound = bound.getLowerValue(); @@ -1002,9 +1218,9 @@ else if (candidate instanceof Between) { * object as appropriate for {@link And}, {@link Or}, {@link Not} respectively. These {@link ResultSet} objects * will take care of performing intersections or unions etc. on the child {@link ResultSet}s. * - * @param query A query representing some assertions which sought objects must match + * @param query A query representing some assertions which sought objects must match * @param queryOptions Optional parameters for the query - * supplied specifying strategy {@link DeduplicationStrategy#LOGICAL_ELIMINATION} + * supplied specifying strategy {@link DeduplicationStrategy#LOGICAL_ELIMINATION} * @return A {@link ResultSet} which provides objects matching the given query */ ResultSet retrieveRecursive(Query query, final QueryOptions queryOptions) { @@ -1017,20 +1233,16 @@ ResultSet retrieveRecursive(Query query, final QueryOptions queryOptions) return resultSetFromStandingQueryIndex; } // ..else no standing query index was available, process the query normally... - - if (query instanceof SimpleQuery) { // No deduplication required for a single SimpleQuery. // Return the ResultSet from the index with the lowest retrieval cost which supports // this query and the attribute on which it is based... return retrieveSimpleQuery((SimpleQuery) query, queryOptions); - } - else if (query instanceof ComparativeQuery) { + } else if (query instanceof ComparativeQuery) { // Return the ResultSet from the index with the lowest retrieval cost which supports // this query and the attribute on which it is based... return retrieveComparativeQuery((ComparativeQuery) query, queryOptions); - } - else if (query instanceof And) { + } else if (query instanceof And) { final And and = (And) query; // Check if we can process this And query from a compound index... @@ -1066,12 +1278,19 @@ public ResultSet next() { if (needToProcessSimpleQueries) { needToProcessSimpleQueries = false; // Retrieve results for simple queries from indexes... - return retrieveIntersectionOfSimpleQueries(and.getSimpleQueries(), queryOptions, indexMergeStrategyEnabled); + ResultSet resultSetSimple = retrieveIntersectionOfSimpleQueries(and.getSimpleQueries(), queryOptions, indexMergeStrategyEnabled); + List resultFromSimple = StreamSupport.stream(resultSetSimple.spliterator(), false).collect(Collectors.toList()); + log.info(String.format("ResultSet %s from retrieveIntersectionOfSimpleQueries for query and.getSimpleQueries(): %s ", resultFromSimple, and.getSimpleQueries())); + return resultSetSimple; + } if (needToProcessComparativeQueries) { needToProcessComparativeQueries = false; // Retrieve results for comparative queries from indexes... - return retrieveIntersectionOfComparativeQueries(and.getComparativeQueries(), queryOptions); + ResultSet comparativeQueryResultSet = retrieveIntersectionOfComparativeQueries(and.getComparativeQueries(), queryOptions); + List resultFromComparative = StreamSupport.stream(comparativeQueryResultSet.spliterator(), false).collect(Collectors.toList()); + log.info(String.format("ResultSet %s from retrieveIntersectionOfComparativeQueries for query and.getComparativeQueries(): %s ", resultFromComparative, and.getComparativeQueries())); + return comparativeQueryResultSet; } // Recursively call this method for logical queries... return retrieveRecursive(logicalQueriesIterator.next(), queryOptions); @@ -1081,8 +1300,7 @@ public ResultSet next() { }; boolean useIndexMergeStrategy = shouldUseIndexMergeStrategy(indexMergeStrategyEnabled, and.hasComparativeQueries(), resultSetsToMerge); return new ResultSetIntersection(resultSetsToMerge, query, queryOptions, useIndexMergeStrategy); - } - else if (query instanceof Or) { + } else if (query instanceof Or) { final Or or = (Or) query; // If the Or query indicates child queries are disjoint, // ignore any instruction to perform deduplication in the queryOptions supplied... @@ -1097,8 +1315,7 @@ public Object get(Object key) { return DeduplicationOption.class.equals(key) ? null : super.get(key); } }; - } - else { + } else { // Use the supplied queryOptions... queryOptionsForOrUnion = queryOptions; } @@ -1140,8 +1357,7 @@ public ResultSet next() { if (DeduplicationOption.isLogicalElimination(queryOptionsForOrUnion)) { boolean useIndexMergeStrategy = shouldUseIndexMergeStrategy(indexMergeStrategyEnabled, or.hasComparativeQueries(), resultSetsToUnion); union = new ResultSetUnion(resultSetsToUnion, query, queryOptions, useIndexMergeStrategy); - } - else { + } else { union = new ResultSetUnionAll(resultSetsToUnion, query, queryOptions); } @@ -1163,16 +1379,14 @@ public boolean isValid(O object, QueryOptions queryOptions) { }; } return union; - } - else if (query instanceof Not) { + } else if (query instanceof Not) { final Not not = (Not) query; // No deduplication required for negation (the entire collection is a Set, contains no duplicates). // Retrieve the ResultSet for the negated query, by calling this method recursively... ResultSet resultSetToNegate = retrieveRecursive(not.getNegatedQuery(), queryOptions); // Return the negation of this result set, by subtracting it from the entire collection of objects... return new ResultSetDifference(getEntireCollectionAsResultSet(query, queryOptions), resultSetToNegate, query, queryOptions, indexMergeStrategyEnabled); - } - else { + } else { throw new IllegalStateException("Unexpected type of query object: " + getClassNameNullSafe(query)); } } @@ -1206,7 +1420,7 @@ else if (query instanceof Not) { * {@link Query#matches(Object, QueryOptions)} to test each object in the smallest set against queries which would match the * more expensive sets, rather than perform several hash lookups and equality tests between multiple sets. * - * @param queries A collection of {@link SimpleQuery} objects to be retrieved and intersected + * @param queries A collection of {@link SimpleQuery} objects to be retrieved and intersected * @param queryOptions Optional parameters for the query * @return A {@link ResultSet} which provides objects matching the intersection of results for each of the * {@link SimpleQuery}s @@ -1221,7 +1435,7 @@ ResultSet retrieveIntersectionOfSimpleQueries(Collection> queriesTyped = (Collection>)(Collection>)queries; + Collection> queriesTyped = (Collection>) (Collection>) queries; Query query = queriesTyped.size() == 1 ? queriesTyped.iterator().next() : new And(queriesTyped); boolean useIndexMergeStrategy = indexMergeStrategyEnabled && indexesAvailableForAllResultSets(resultSets); @@ -1242,7 +1456,7 @@ ResultSet retrieveIntersectionOfComparativeQueries(Collection> queriesTyped = (Collection>)(Collection>)queries; + Collection> queriesTyped = (Collection>) (Collection>) queries; Query query = queriesTyped.size() == 1 ? queriesTyped.iterator().next() : new And(queriesTyped); // We always use index merge strategy to merge results for comparative queries... @@ -1268,9 +1482,9 @@ ResultSet retrieveIntersectionOfComparativeQueries(Collection> iterator() { return new UnmodifiableIterator>() { Iterator> queriesIterator = queries.iterator(); + @Override public boolean hasNext() { return queriesIterator.hasNext(); @@ -1294,7 +1509,7 @@ public ResultSet next() { } }; @SuppressWarnings("unchecked") - Collection> queriesTyped = (Collection>)(Collection>)queries; + Collection> queriesTyped = (Collection>) (Collection>) queries; Query query = queriesTyped.size() == 1 ? queriesTyped.iterator().next() : new Or(queriesTyped); // Perform deduplication as necessary... if (DeduplicationOption.isLogicalElimination(queryOptions)) { @@ -1302,8 +1517,7 @@ public ResultSet next() { boolean indexMergeStrategyEnabled = isFlagEnabled(queryOptions, PREFER_INDEX_MERGE_STRATEGY); boolean useIndexMergeStrategy = indexMergeStrategyEnabled && indexesAvailableForAllResultSets(resultSetsToUnion); return new ResultSetUnion(resultSetsToUnion, query, queryOptions, useIndexMergeStrategy); - } - else { + } else { return new ResultSetUnionAll(resultSetsToUnion, query, queryOptions); } } @@ -1319,6 +1533,7 @@ public Iterator> iterator() { return new UnmodifiableIterator>() { Iterator> queriesIterator = queries.iterator(); + @Override public boolean hasNext() { return queriesIterator.hasNext(); @@ -1332,14 +1547,13 @@ public ResultSet next() { } }; @SuppressWarnings("unchecked") - Collection> queriesTyped = (Collection>)(Collection>)queries; + Collection> queriesTyped = (Collection>) (Collection>) queries; Query query = queriesTyped.size() == 1 ? queriesTyped.iterator().next() : new Or(queriesTyped); // Perform deduplication as necessary... if (DeduplicationOption.isLogicalElimination(queryOptions)) { // Note: we always use the index merge strategy to merge results for comparative queries... return new ResultSetUnion(resultSetsToUnion, query, queryOptions, true); - } - else { + } else { return new ResultSetUnionAll(resultSetsToUnion, query, queryOptions); } } @@ -1349,7 +1563,7 @@ public ResultSet next() { * a {@link ResultSet} which does so. * If the query cannot be answered from a standing query index, returns null. * - * @param query The query to evaluate + * @param query The query to evaluate * @param queryOptions Query options supplied for the query * @return A {@link ResultSet} which answers the query from a standing query index, or null if no such index * is available @@ -1361,8 +1575,7 @@ ResultSet retrieveFromStandingQueryIndexIfAvailable(Query query, final Que // No deduplication required for standing queries. if (standingQueryIndex instanceof StandingQueryIndex) { return standingQueryIndex.retrieve(query, queryOptions); - } - else { + } else { return standingQueryIndex.retrieve(equal(forStandingQuery(query), Boolean.TRUE), queryOptions); } } // else no suitable standing query index exists, process the query normally... @@ -1405,6 +1618,7 @@ public boolean perform(Index index) { /** * {@inheritDoc} + * * @param queryOptions */ @Override @@ -1452,6 +1666,7 @@ interface IndexOperation { * Iterates through all indexes and for each index invokes the given index operation. If the operation returns * false for any index, stops iterating and returns false. If the operation returns true for every index, * returns true after all indexes have been iterated. + * * @param indexOperation The operation to perform on each index. * @return true if the operation returned true for all indexes and so all indexes were iterated, false if the * operation returned false for any index and so iteration was stopped diff --git a/code/src/main/java/com/googlecode/cqengine/engine/QueryEngine.java b/code/src/main/java/com/googlecode/cqengine/engine/QueryEngine.java index 71e3bb282..b00daa6c4 100644 --- a/code/src/main/java/com/googlecode/cqengine/engine/QueryEngine.java +++ b/code/src/main/java/com/googlecode/cqengine/engine/QueryEngine.java @@ -16,6 +16,8 @@ package com.googlecode.cqengine.engine; import com.googlecode.cqengine.index.Index; +import com.googlecode.cqengine.index.indexOrdering.ConcurrentInvertedRadixTreesHolder; +import com.googlecode.cqengine.index.indexOrdering.IConcurrentInvertedRadixTreesHolder; import com.googlecode.cqengine.query.Query; import com.googlecode.cqengine.query.option.QueryOptions; import com.googlecode.cqengine.resultset.ResultSet; @@ -64,4 +66,6 @@ public interface QueryEngine { * {@link #addIndex(com.googlecode.cqengine.index.Index, QueryOptions)} method */ public Iterable> getIndexes(); + + void setConcurrentInvertedRadixTree(IConcurrentInvertedRadixTreesHolder singletonConcurrentTreeHolder); } diff --git a/code/src/main/java/com/googlecode/cqengine/entity/MapEntity.java b/code/src/main/java/com/googlecode/cqengine/entity/MapEntity.java index 81cbfa99a..351e723a5 100644 --- a/code/src/main/java/com/googlecode/cqengine/entity/MapEntity.java +++ b/code/src/main/java/com/googlecode/cqengine/entity/MapEntity.java @@ -22,7 +22,7 @@ import java.util.Set; /** - * Wrapper for Map to allow efficient use in an IndexCollection. + * Wrapper for Map to allow efficient use in an . * MapEntities can be created via {@link QueryFactory#mapEntity(Map)}. Attributes can be created to read the entries * in these maps, using {@link QueryFactory#mapAttribute(Object, Class)}. *

diff --git a/code/src/main/java/com/googlecode/cqengine/index/indexOrdering/ConcurrentInvertedRadixTreesHolder.java b/code/src/main/java/com/googlecode/cqengine/index/indexOrdering/ConcurrentInvertedRadixTreesHolder.java new file mode 100644 index 000000000..f9c0b23d3 --- /dev/null +++ b/code/src/main/java/com/googlecode/cqengine/index/indexOrdering/ConcurrentInvertedRadixTreesHolder.java @@ -0,0 +1,34 @@ +package com.googlecode.cqengine.index.indexOrdering; + +import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree; + +import java.util.HashMap; +import java.util.Map; + +public class ConcurrentInvertedRadixTreesHolder implements IConcurrentInvertedRadixTreesHolder { + + private final Map concurrentInvertedRadixTreeHashMap; + + + public ConcurrentInvertedRadixTreesHolder() { + this.concurrentInvertedRadixTreeHashMap = new HashMap<>(); + } + + public boolean containsKey(String fieldName) { + return concurrentInvertedRadixTreeHashMap.containsKey(fieldName); + } + + public IndexedConcurrentInvertedRadixTree getConcurrentInvertedRadixTree(String fieldName) { + return concurrentInvertedRadixTreeHashMap.get(fieldName); + } + + public void addConcurrentInvertedRadixTree(String fieldName, IndexedConcurrentInvertedRadixTree concurrentInvertedRadixTree) { + concurrentInvertedRadixTreeHashMap.put(fieldName, concurrentInvertedRadixTree); + } + + public void deleteIndexedConcurrentInvertedRadixTree(String fieldName) { + concurrentInvertedRadixTreeHashMap.remove(fieldName); + } + + +} diff --git a/code/src/main/java/com/googlecode/cqengine/index/indexOrdering/IConcurrentInvertedRadixTreesHolder.java b/code/src/main/java/com/googlecode/cqengine/index/indexOrdering/IConcurrentInvertedRadixTreesHolder.java new file mode 100644 index 000000000..16051ce35 --- /dev/null +++ b/code/src/main/java/com/googlecode/cqengine/index/indexOrdering/IConcurrentInvertedRadixTreesHolder.java @@ -0,0 +1,19 @@ +package com.googlecode.cqengine.index.indexOrdering; + +import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree; + +public interface IConcurrentInvertedRadixTreesHolder { + + boolean containsKey(String fieldName); + + IndexedConcurrentInvertedRadixTree getConcurrentInvertedRadixTree(String fieldName); + + + void addConcurrentInvertedRadixTree(String fieldName, IndexedConcurrentInvertedRadixTree concurrentInvertedRadixTree); + + + + void deleteIndexedConcurrentInvertedRadixTree(String fieldName); + + +} diff --git a/code/src/main/java/com/googlecode/cqengine/index/indexOrdering/IndexedConcurrentInvertedRadixTree.java b/code/src/main/java/com/googlecode/cqengine/index/indexOrdering/IndexedConcurrentInvertedRadixTree.java new file mode 100644 index 000000000..d4a477d6c --- /dev/null +++ b/code/src/main/java/com/googlecode/cqengine/index/indexOrdering/IndexedConcurrentInvertedRadixTree.java @@ -0,0 +1,47 @@ +package com.googlecode.cqengine.index.indexOrdering; + +import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree; + +import java.util.Objects; + +public class IndexedConcurrentInvertedRadixTree { + + private final ConcurrentInvertedRadixTree concurrentInvertedRadixTree; + + private Integer index; + + public IndexedConcurrentInvertedRadixTree(ConcurrentInvertedRadixTree concurrentInvertedRadixTree) { + this.concurrentInvertedRadixTree = concurrentInvertedRadixTree; + index = 0; + } + + public ConcurrentInvertedRadixTree getConcurrentInvertedRadixTree() { + return concurrentInvertedRadixTree; + } + + public Integer getIndex() { + return index; + } + + public void setIndex(Integer index) { + this.index = index; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof IndexedConcurrentInvertedRadixTree)) { + return false; + + } + IndexedConcurrentInvertedRadixTree that = (IndexedConcurrentInvertedRadixTree) o; + return concurrentInvertedRadixTree.equals(that.concurrentInvertedRadixTree) && index.equals(that.index); + } + + @Override + public int hashCode() { + return Objects.hash(concurrentInvertedRadixTree, index); + } +} diff --git a/code/src/main/java/com/googlecode/cqengine/query/QueryFactory.java b/code/src/main/java/com/googlecode/cqengine/query/QueryFactory.java index a28072fee..478064b4f 100644 --- a/code/src/main/java/com/googlecode/cqengine/query/QueryFactory.java +++ b/code/src/main/java/com/googlecode/cqengine/query/QueryFactory.java @@ -717,6 +717,17 @@ public static FlagsDisabled disableFlags(Object... flags) { return result; } + + + public static AttrObjectOptions applyAttrObjectOptions(AttrObjectOption... attrObjectOptions) { + return new AttrObjectOptions(Arrays.asList(attrObjectOptions)); + + } + + public static AttrObjectOption attrObjectOption(Object key, Object value) { + return new AttrObjectOption(key, value); + } + /** * Creates a {@link Thresholds} object which may be added to query options. * It encapsulates individual {@link Threshold} objects which are to override default values for thresholds which diff --git a/code/src/main/java/com/googlecode/cqengine/query/option/AttrObjectOption.java b/code/src/main/java/com/googlecode/cqengine/query/option/AttrObjectOption.java new file mode 100644 index 000000000..9059f9708 --- /dev/null +++ b/code/src/main/java/com/googlecode/cqengine/query/option/AttrObjectOption.java @@ -0,0 +1,70 @@ +/** + * Copyright 2012-2015 Niall Gallagher + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.cqengine.query.option; + +public class AttrObjectOption { + + private final Object key; + private final Object value; + + public AttrObjectOption(Object key, Object value) { + this.key = key; + this.value = value; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof AttrObjectOption)) { + return false; + } + + AttrObjectOption attrObjectOption = (AttrObjectOption) o; + + if (!key.equals(attrObjectOption.key)) { + return false; + } + return value.equals(attrObjectOption.value); + + } + + + public Object getKey() { + return key; + } + + public Object getValue() { + return value; + } + + @Override + public int hashCode() { + int result = key.hashCode(); + result = 31 * result + value.hashCode(); + return result; + } + + + @Override + public String toString() { + return "AttrObjectOption{" + + "key=" + key + + ", value=" + value + + '}'; + } +} diff --git a/code/src/main/java/com/googlecode/cqengine/query/option/AttrObjectOptions.java b/code/src/main/java/com/googlecode/cqengine/query/option/AttrObjectOptions.java new file mode 100644 index 000000000..b1f9983f9 --- /dev/null +++ b/code/src/main/java/com/googlecode/cqengine/query/option/AttrObjectOptions.java @@ -0,0 +1,62 @@ +/** + * Copyright 2012-2015 Niall Gallagher + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.cqengine.query.option; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; + +public class AttrObjectOptions { + + final Map attrStringOptions = new LinkedHashMap(); + + public AttrObjectOptions(Collection attrObjectOptions) { + for (AttrObjectOption attrObjectOption : attrObjectOptions) { + this.attrStringOptions.put(attrObjectOption.getKey(), attrObjectOption.getValue()); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof AttrObjectOptions)) { + return false; + } + AttrObjectOptions that = (AttrObjectOptions) o; + return attrStringOptions.equals(that.attrStringOptions); + } + + @Override + public int hashCode() { + return attrStringOptions.hashCode(); + } + + public Object getAttrObjectOption(Object key) { + return attrStringOptions.get(key); + } + + @Override + public String toString() { + return attrStringOptions.toString(); + } + + public static Object getAttrObjectOption(QueryOptions queryOptions, Object key) { + AttrObjectOptions attrObjectOptions = queryOptions.get(AttrObjectOptions.class); + return attrObjectOptions == null ? null : attrObjectOptions.getAttrObjectOption(key); + } +} diff --git a/code/src/main/java/com/googlecode/cqengine/query/option/ConcurrentRadixTreeLongestPrefixMatch.java b/code/src/main/java/com/googlecode/cqengine/query/option/ConcurrentRadixTreeLongestPrefixMatch.java new file mode 100644 index 000000000..bb3906377 --- /dev/null +++ b/code/src/main/java/com/googlecode/cqengine/query/option/ConcurrentRadixTreeLongestPrefixMatch.java @@ -0,0 +1,8 @@ +package com.googlecode.cqengine.query.option; + +public enum ConcurrentRadixTreeLongestPrefixMatch { + + CONCURRENT_RADIX_TREE_LONGEST_PREFIX_MATCH_BY_ATTRIBUTES, + + CONCURRENT_RADIX_TREE_LONGEST_PREFIX_MATCH_BY_VALUES; +} diff --git a/code/src/main/java/com/googlecode/cqengine/query/option/EngineFlags.java b/code/src/main/java/com/googlecode/cqengine/query/option/EngineFlags.java index d86ed4aa3..0ceab2c78 100644 --- a/code/src/main/java/com/googlecode/cqengine/query/option/EngineFlags.java +++ b/code/src/main/java/com/googlecode/cqengine/query/option/EngineFlags.java @@ -77,5 +77,7 @@ public enum EngineFlags { * ordering. This will improve retrieval speed, at the expense of allowing the relative ordering of objects having * one attribute value in common, and having other differing attribute values, to be slightly inexact. */ - INDEX_ORDERING_ALLOW_FAST_ORDERING_OF_MULTI_VALUED_ATTRIBUTES + INDEX_ORDERING_ALLOW_FAST_ORDERING_OF_MULTI_VALUED_ATTRIBUTES, + + INDEX_ORDERING_ALLOW_COMPUTE_LONGEST_PREFIX_MATCH } diff --git a/code/src/main/java/com/googlecode/cqengine/query/option/LongestPrefixMatchStrategy.java b/code/src/main/java/com/googlecode/cqengine/query/option/LongestPrefixMatchStrategy.java new file mode 100644 index 000000000..968ddd16d --- /dev/null +++ b/code/src/main/java/com/googlecode/cqengine/query/option/LongestPrefixMatchStrategy.java @@ -0,0 +1,23 @@ +/** + * Copyright 2012-2015 Niall Gallagher + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.cqengine.query.option; + +/** + * @author Niall Gallagher + */ +public enum LongestPrefixMatchStrategy { + LONGEST_PREFIX_MATCH_CONCURRENT_TREES +} diff --git a/code/src/main/java/com/googlecode/cqengine/resultset/connective/ResultSetIntersection.java b/code/src/main/java/com/googlecode/cqengine/resultset/connective/ResultSetIntersection.java index 4e436917f..a6925a62d 100644 --- a/code/src/main/java/com/googlecode/cqengine/resultset/connective/ResultSetIntersection.java +++ b/code/src/main/java/com/googlecode/cqengine/resultset/connective/ResultSetIntersection.java @@ -22,14 +22,18 @@ import com.googlecode.cqengine.resultset.ResultSet; import com.googlecode.cqengine.resultset.common.QueryCostComparators; import com.googlecode.cqengine.resultset.iterator.IteratorUtil; +import lombok.extern.slf4j.Slf4j; import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; /** * A ResultSet which provides a view onto the intersection of other ResultSets. * * @author Niall Gallagher */ +@Slf4j public class ResultSetIntersection extends ResultSet { final Query query; @@ -39,11 +43,27 @@ public class ResultSetIntersection extends ResultSet { final boolean useIndexMergeStrategy; public ResultSetIntersection(Iterable> resultSets, Query query, QueryOptions queryOptions, boolean useIndexMergeStrategy) { + log.info(String.format("Method ResultSetIntersection, query %s,queryOptions %s",query,queryOptions)); this.query = query; this.queryOptions = queryOptions; // Sort the supplied result sets in ascending order of merge cost... + + log.info("Before sort:"); + int index = 0; + for(ResultSet resultSet:resultSets){ + List resultSetList = StreamSupport.stream(resultSet.spliterator(), false).collect(Collectors.toList()); + log.info(String.format("ResultSet %s in iteration : %d ",resultSetList,(index+1))); + index++; + } List> sortedResultSets = ResultSets.wrapWithCostCachingIfNecessary(resultSets); Collections.sort(sortedResultSets, QueryCostComparators.getMergeCostComparator()); + log.info("After sort:"); + index = 0; + for(ResultSet resultSet:sortedResultSets){ + List resultSetList = StreamSupport.stream(resultSet.spliterator(), false).collect(Collectors.toList()); + log.info(String.format("ResultSet %s in iteration : %d ",resultSetList,(index+1))); + index++; + } this.resultSets = sortedResultSets; this.useIndexMergeStrategy = useIndexMergeStrategy; } diff --git a/code/src/test/java/com/googlecode/cqengine/examples/ordering/LongestPrefixMatchExampleCodeRun.java b/code/src/test/java/com/googlecode/cqengine/examples/ordering/LongestPrefixMatchExampleCodeRun.java new file mode 100644 index 000000000..9195175da --- /dev/null +++ b/code/src/test/java/com/googlecode/cqengine/examples/ordering/LongestPrefixMatchExampleCodeRun.java @@ -0,0 +1,269 @@ +package com.googlecode.cqengine.examples.ordering; + +import com.googlecode.concurrenttrees.common.PrettyPrinter; +import com.googlecode.concurrenttrees.radix.node.NodeFactory; +import com.googlecode.concurrenttrees.radix.node.concrete.DefaultCharArrayNodeFactory; +import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree; +import com.googlecode.cqengine.ConcurrentIndexedCollection; +import com.googlecode.cqengine.IndexedCollection; +import com.googlecode.cqengine.attribute.Attribute; +import com.googlecode.cqengine.index.hash.HashIndex; +import com.googlecode.cqengine.index.indexOrdering.*; +import com.googlecode.cqengine.index.navigable.NavigableIndex; +import com.googlecode.cqengine.query.Query; +import com.googlecode.cqengine.query.QueryFactory; +import com.googlecode.cqengine.query.option.ConcurrentRadixTreeLongestPrefixMatch; +import com.googlecode.cqengine.query.option.QueryOptions; +import com.googlecode.cqengine.resultset.ResultSet; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import static com.googlecode.cqengine.query.QueryFactory.*; +import static com.googlecode.cqengine.query.option.EngineThresholds.INDEX_ORDERING_SELECTIVITY; + +public class LongestPrefixMatchExampleCodeRun { + + + private final NodeFactory nodeFactory = new DefaultCharArrayNodeFactory(); + + protected NodeFactory getNodeFactory() { + return nodeFactory; + } + + + @Test + public void testNewDesignedSolutionOneColumnDefinedAsLongest() { + + // Indexed collection + IndexedCollection longestPrefixMatchExampleCodes = new ConcurrentIndexedCollection<>(); + + //get the IndexOrderingConcurrentTreeHolder from the cqengine + IConcurrentInvertedRadixTreesHolder singletonConcurrentTreeHolder = new ConcurrentInvertedRadixTreesHolder(); + + // some indexes + //longestPrefixMatchExampleCodes.addIndex(NavigableIndex.onAttribute(LongestPrefixMatchExampleCode.A_NUMBER)); + longestPrefixMatchExampleCodes.addIndex(HashIndex.onAttribute(LongestPrefixMatchOneColumnExampleCode.bVALID_FROM)); + longestPrefixMatchExampleCodes.addIndex(HashIndex.onAttribute(LongestPrefixMatchOneColumnExampleCode.cVALID_TO)); + // add cars objects to collection- + longestPrefixMatchExampleCodes.add(new LongestPrefixMatchOneColumnExampleCode("89761", new Long(4), new Long(7), "A1")); + longestPrefixMatchExampleCodes.add(new LongestPrefixMatchOneColumnExampleCode("67894", new Long(4), new Long(7), "A1")); + longestPrefixMatchExampleCodes.add(new LongestPrefixMatchOneColumnExampleCode("32221", new Long(11), new Long(17), "A1")); + longestPrefixMatchExampleCodes.add(new LongestPrefixMatchOneColumnExampleCode("32", new Long(9), new Long(16), "C1")); + longestPrefixMatchExampleCodes.add(new LongestPrefixMatchOneColumnExampleCode("32", new Long(9), new Long(18), "D1")); + longestPrefixMatchExampleCodes.add(new LongestPrefixMatchOneColumnExampleCode("32", new Long(7), new Long(15), "D1")); + longestPrefixMatchExampleCodes.add(new LongestPrefixMatchOneColumnExampleCode("328", new Long(9), new Long(10), "E1")); + longestPrefixMatchExampleCodes.add(new LongestPrefixMatchOneColumnExampleCode("4561", new Long(8), new Long(15), "F1")); + + // run some queries + System.out.println("LongestPrefixMatchExample Table"); + + // Query time case 1: between valid from and valid to + Query queryTime_case1 = and(lessThanOrEqualTo(LongestPrefixMatchOneColumnExampleCode.bVALID_FROM, new Long(10)), greaterThanOrEqualTo(LongestPrefixMatchOneColumnExampleCode.cVALID_TO, new Long(10))); + // two cases combined +// Query query_Time = or(queryTime_case1, queryTime1_case2); + Query query_Time = queryTime_case1; + + longestPrefixMatchExampleCodes.addIndex(NavigableIndex.onAttribute(LongestPrefixMatchOneColumnExampleCode.a_NUMBER)); + + List lookups = new ArrayList<>(); + + lookups.add("MONATIOANLs"); + + List> attributeList = new ArrayList<>(); + + attributeList.add(LongestPrefixMatchOneColumnExampleCode.a_NUMBER); + + + List attributesValues = new ArrayList<>(); + + attributesValues.add("322211"); + + + QueryOptions queryOptions = QueryFactory.queryOptions(orderBy(descending(LongestPrefixMatchOneColumnExampleCode.a_NUMBER)), + applyThresholds(threshold(INDEX_ORDERING_SELECTIVITY, 1.0)), + applyAttrObjectOptions(attrObjectOption(ConcurrentRadixTreeLongestPrefixMatch.CONCURRENT_RADIX_TREE_LONGEST_PREFIX_MATCH_BY_ATTRIBUTES, attributeList), + attrObjectOption(ConcurrentRadixTreeLongestPrefixMatch.CONCURRENT_RADIX_TREE_LONGEST_PREFIX_MATCH_BY_VALUES, attributesValues))); + + //creation of the concurrent radix tree + + ConcurrentInvertedRadixTree tree1 = new ConcurrentInvertedRadixTree(nodeFactory); + + IndexedConcurrentInvertedRadixTree indexedConcurrentInvertedRadixTree = new IndexedConcurrentInvertedRadixTree(tree1); + + List trees = new ArrayList<>(); + + trees.add(indexedConcurrentInvertedRadixTree); + + + longestPrefixMatchExampleCodes.forEach(element -> { + tree1.put(element.getANumber(), indexedConcurrentInvertedRadixTree.getIndex()); + Integer index = indexedConcurrentInvertedRadixTree.getIndex(); + index++; + indexedConcurrentInvertedRadixTree.setIndex(index); + }); + + + AtomicInteger indexForPrint = new AtomicInteger(0); + attributeList.forEach(element -> { + System.out.println(String.format("Pretty print for tree of Field %s: ", attributeList.get(indexForPrint.get()).getAttributeName())); + + String actual = PrettyPrinter.prettyPrint(trees.get(indexForPrint.get()).getConcurrentInvertedRadixTree()); + + System.out.println(actual); + + indexForPrint.getAndIncrement(); + }); + + QueryOptions finalQueryOptions = queryOptions; + AtomicInteger index = new AtomicInteger(0); + attributeList.forEach(e -> { + singletonConcurrentTreeHolder.addConcurrentInvertedRadixTree(attributeList.get(index.get()).getAttributeName(), trees.get(index.get())); + index.getAndIncrement(); + }); + + + longestPrefixMatchExampleCodes.setConcurrentInvertedRadixTree(singletonConcurrentTreeHolder); + System.out.println("finalResult:"); + + + + + ResultSet longestPrefixMatchExampleCodeResultSet = longestPrefixMatchExampleCodes.retrieve(query_Time, queryOptions); + + longestPrefixMatchExampleCodeResultSet.forEach(System.out::println); + + + } + + + @Test + public void testNewDesignedSolutionTwoColumnsDefinedAsLongest() { + + // Indexed collection + IndexedCollection longestPrefixMatchExampleCodes = new ConcurrentIndexedCollection<>(); + + //get the IndexOrderingConcurrentTreeHolder from the cqengine + IConcurrentInvertedRadixTreesHolder singletonConcurrentTreeHolder = new ConcurrentInvertedRadixTreesHolder(); + + // some indexes + //longestPrefixMatchExampleCodes.addIndex(NavigableIndex.onAttribute(LongestPrefixMatchExampleCode.A_NUMBER)); + longestPrefixMatchExampleCodes.addIndex(HashIndex.onAttribute(LongestPrefixMatchTwoColumnsExampleCode.bVALID_FROM)); + longestPrefixMatchExampleCodes.addIndex(HashIndex.onAttribute(LongestPrefixMatchTwoColumnsExampleCode.cVALID_TO)); + + LongestPrefixMatchTwoColumnsExampleCode expectedLongest = new LongestPrefixMatchTwoColumnsExampleCode("3222", "4567", new Long(9), new Long(16), "C1"); + // add cars objects to collection- + longestPrefixMatchExampleCodes.add(new LongestPrefixMatchTwoColumnsExampleCode("89761", "9876", new Long(4), new Long(7), "A1")); + longestPrefixMatchExampleCodes.add(new LongestPrefixMatchTwoColumnsExampleCode("67894", "45678", new Long(4), new Long(7), "A1")); + longestPrefixMatchExampleCodes.add(new LongestPrefixMatchTwoColumnsExampleCode("32221", "45671", new Long(11), new Long(17), "A1")); + longestPrefixMatchExampleCodes.add(new LongestPrefixMatchTwoColumnsExampleCode("3222", "4567", new Long(12), new Long(16), "C1")); + longestPrefixMatchExampleCodes.add(new LongestPrefixMatchTwoColumnsExampleCode("3222", "4567", new Long(9), new Long(18), "D1")); + longestPrefixMatchExampleCodes.add(new LongestPrefixMatchTwoColumnsExampleCode("3222", "4567", new Long(7), new Long(15), "D1")); + longestPrefixMatchExampleCodes.add(new LongestPrefixMatchTwoColumnsExampleCode("328", "49", new Long(9), new Long(10), "E1")); + longestPrefixMatchExampleCodes.add(new LongestPrefixMatchTwoColumnsExampleCode("4561", "45671", new Long(8), new Long(15), "F1")); + + // run some queries + System.out.println("LongestPrefixMatchExample Table"); + + // Query time case 1: between valid from and valid to + Query queryTime_case1 = and(lessThanOrEqualTo(LongestPrefixMatchTwoColumnsExampleCode.bVALID_FROM, new Long(10)), greaterThanOrEqualTo(LongestPrefixMatchTwoColumnsExampleCode.cVALID_TO, new Long(10))); + // two cases combined +// Query query_Time = or(queryTime_case1, queryTime1_case2); + Query query_Time = queryTime_case1; + + //longestPrefixMatchExampleCodes.addIndex(NavigableIndex.onAttribute(forObjectsMissing(LongestPrefixMatchTwoColumnsExampleCode.a_NUMBER))); + + longestPrefixMatchExampleCodes.addIndex(NavigableIndex.onAttribute(LongestPrefixMatchTwoColumnsExampleCode.a_NUMBER)); + + + //longestPrefixMatchExampleCodes.addIndex(NavigableIndex.onAttribute(forObjectsMissing(LongestPrefixMatchTwoColumnsExampleCode.b_NUMBER))); + + longestPrefixMatchExampleCodes.addIndex(NavigableIndex.onAttribute(LongestPrefixMatchTwoColumnsExampleCode.b_NUMBER)); + + + List> attributeList = new ArrayList<>(); + + attributeList.add(LongestPrefixMatchTwoColumnsExampleCode.a_NUMBER); + + attributeList.add(LongestPrefixMatchTwoColumnsExampleCode.b_NUMBER); + + + List attributesValues = new ArrayList<>(); + + attributesValues.add("322211"); + + attributesValues.add("45671"); + + + QueryOptions queryOptions = QueryFactory.queryOptions(orderBy(descending(LongestPrefixMatchTwoColumnsExampleCode.a_NUMBER) + , descending(LongestPrefixMatchTwoColumnsExampleCode.b_NUMBER)), + applyThresholds(threshold(INDEX_ORDERING_SELECTIVITY, 1.0)), + applyAttrObjectOptions(attrObjectOption(ConcurrentRadixTreeLongestPrefixMatch.CONCURRENT_RADIX_TREE_LONGEST_PREFIX_MATCH_BY_ATTRIBUTES, attributeList), + attrObjectOption(ConcurrentRadixTreeLongestPrefixMatch.CONCURRENT_RADIX_TREE_LONGEST_PREFIX_MATCH_BY_VALUES, attributesValues))); + + //creation of the concurrent radix tree + + ConcurrentInvertedRadixTree tree1 = new ConcurrentInvertedRadixTree(nodeFactory); + + + ConcurrentInvertedRadixTree tree2 = new ConcurrentInvertedRadixTree(nodeFactory); + + + IndexedConcurrentInvertedRadixTree indexedConcurrentInvertedRadixTree1 = new IndexedConcurrentInvertedRadixTree(tree1); + + IndexedConcurrentInvertedRadixTree indexedConcurrentInvertedRadixTree2 = new IndexedConcurrentInvertedRadixTree(tree2); + + List trees = new ArrayList<>(); + + trees.add(indexedConcurrentInvertedRadixTree1); + + trees.add(indexedConcurrentInvertedRadixTree2); + + AtomicInteger indexForTree = new AtomicInteger(0); + longestPrefixMatchExampleCodes.forEach(element -> { + Integer indexForA = trees.get(0).getIndex(); + tree1.put(element.getANumber(), indexForA); + indexForA++; + trees.get(0).setIndex(indexForA); + Integer indexForB = trees.get(1).getIndex(); + tree2.put(element.getBNumber(), indexForB); + indexForB++; + trees.get(1).setIndex(indexForB); + }); + + + AtomicInteger indexForPrint = new AtomicInteger(0); + attributeList.forEach(element -> { + System.out.println(String.format("Pretty print for tree of Field %s: ", attributeList.get(indexForPrint.get()).getAttributeName())); + + String actual = PrettyPrinter.prettyPrint(trees.get(indexForPrint.get()).getConcurrentInvertedRadixTree()); + + System.out.println(actual); + + indexForPrint.getAndIncrement(); + }); + + QueryOptions finalQueryOptions = queryOptions; + AtomicInteger index = new AtomicInteger(0); + attributeList.forEach(e -> { + singletonConcurrentTreeHolder.addConcurrentInvertedRadixTree(attributeList.get(index.get()).getAttributeName(), trees.get(index.get())); + index.getAndIncrement(); + }); + + + longestPrefixMatchExampleCodes.setConcurrentInvertedRadixTree(singletonConcurrentTreeHolder); + + + System.out.println("finalResult:"); + + ResultSet longestPrefixMatchExampleCodeResultSet = longestPrefixMatchExampleCodes.retrieve(query_Time, queryOptions); + + + longestPrefixMatchExampleCodeResultSet.forEach(System.out::println); + + + } +} \ No newline at end of file diff --git a/code/src/test/java/com/googlecode/cqengine/examples/ordering/LongestPrefixMatchOneColumnExampleCode.java b/code/src/test/java/com/googlecode/cqengine/examples/ordering/LongestPrefixMatchOneColumnExampleCode.java new file mode 100644 index 000000000..1b85aefd7 --- /dev/null +++ b/code/src/test/java/com/googlecode/cqengine/examples/ordering/LongestPrefixMatchOneColumnExampleCode.java @@ -0,0 +1,84 @@ +package com.googlecode.cqengine.examples.ordering; + +import com.googlecode.cqengine.attribute.Attribute; +import com.googlecode.cqengine.attribute.SimpleAttribute; +import com.googlecode.cqengine.attribute.SimpleNullableAttribute; +import com.googlecode.cqengine.query.option.QueryOptions; + +public class LongestPrefixMatchOneColumnExampleCode { + private String aNumber; + private Long bValidFrom; + private Long cValidTo; + private String dResult; + + public LongestPrefixMatchOneColumnExampleCode(String aNumber, Long bValidFrom, Long cValidTo, String dResult) { + this.aNumber = aNumber; + this.bValidFrom = bValidFrom; + this.cValidTo = cValidTo; + this.dResult = dResult; + } + + public static Attribute a_NUMBER = new SimpleAttribute("aNumber") { + @Override + public String getValue(LongestPrefixMatchOneColumnExampleCode o, QueryOptions queryOptions) { + return o.getANumber(); + } + }; + + public static Attribute bVALID_FROM = new SimpleNullableAttribute("bValidFrom") { + @Override + public Long getValue(LongestPrefixMatchOneColumnExampleCode o, QueryOptions queryOptions) { + return o.getBValidFrom(); + } + }; + + public static Attribute cVALID_TO = new SimpleNullableAttribute("cValidTo") { + @Override + public Long getValue(LongestPrefixMatchOneColumnExampleCode o, QueryOptions queryOptions) { + return o.getCValidTo(); + } + }; + + public String getDResult() { + return dResult; + } + + public void setDResult(String dResult) { + this.dResult = dResult; + } + + public Long getBValidFrom() { + return bValidFrom; + } + + public void setBValidFrom(Long bValidFrom) { + this.bValidFrom = bValidFrom; + } + + public Long getCValidTo() { + return cValidTo; + } + + public void setCValidTo(Long cValidTo) { + this.cValidTo = cValidTo; + } + + public String getANumber() { + return aNumber; + } + + public void setANumber(String aNumber) { + this.aNumber = aNumber; + } + + + @Override + public String toString() { + return "LongestPrefixMatchOneColumnExampleCode{" + + "aNumber='" + aNumber + '\'' + + ", bValidFrom=" + bValidFrom + + ", cValidTo=" + cValidTo + + ", dResult='" + dResult + '\'' + + '}'; + } +} diff --git a/code/src/test/java/com/googlecode/cqengine/examples/ordering/LongestPrefixMatchTwoColumnsExampleCode.java b/code/src/test/java/com/googlecode/cqengine/examples/ordering/LongestPrefixMatchTwoColumnsExampleCode.java new file mode 100644 index 000000000..e1dc8d098 --- /dev/null +++ b/code/src/test/java/com/googlecode/cqengine/examples/ordering/LongestPrefixMatchTwoColumnsExampleCode.java @@ -0,0 +1,103 @@ +package com.googlecode.cqengine.examples.ordering; + +import com.googlecode.cqengine.attribute.Attribute; +import com.googlecode.cqengine.attribute.SimpleAttribute; +import com.googlecode.cqengine.attribute.SimpleNullableAttribute; +import com.googlecode.cqengine.query.option.QueryOptions; + +public class LongestPrefixMatchTwoColumnsExampleCode { + private String aNumber; + private String bNumber; + private Long bValidFrom; + private Long cValidTo; + private String dResult; + + + public LongestPrefixMatchTwoColumnsExampleCode(String aNumber, String bNumber, Long bValidFrom, Long cValidTo, String dResult) { + this.aNumber = aNumber; + this.bNumber = bNumber; + this.bValidFrom = bValidFrom; + this.cValidTo = cValidTo; + this.dResult = dResult; + } + + public static Attribute a_NUMBER = new SimpleAttribute("aNumber") { + @Override + public String getValue(LongestPrefixMatchTwoColumnsExampleCode o, QueryOptions queryOptions) { + return o.getANumber(); + } + }; + + public static Attribute b_NUMBER = new SimpleAttribute("bNumber") { + @Override + public String getValue(LongestPrefixMatchTwoColumnsExampleCode o, QueryOptions queryOptions) { + return o.getBNumber(); + } + }; + + public static Attribute bVALID_FROM = new SimpleNullableAttribute("bValidFrom") { + @Override + public Long getValue(LongestPrefixMatchTwoColumnsExampleCode o, QueryOptions queryOptions) { + return o.getBValidFrom(); + } + }; + + public static Attribute cVALID_TO = new SimpleNullableAttribute("cValidTo") { + @Override + public Long getValue(LongestPrefixMatchTwoColumnsExampleCode o, QueryOptions queryOptions) { + return o.getCValidTo(); + } + }; + + public String getDResult() { + return dResult; + } + + public void setDResult(String dResult) { + this.dResult = dResult; + } + + public Long getBValidFrom() { + return bValidFrom; + } + + public void setBValidFrom(Long bValidFrom) { + this.bValidFrom = bValidFrom; + } + + public Long getCValidTo() { + return cValidTo; + } + + public void setCValidTo(Long cValidTo) { + this.cValidTo = cValidTo; + } + + public String getANumber() { + return aNumber; + } + + public void setANumber(String aNumber) { + this.aNumber = aNumber; + } + + + public String getBNumber() { + return bNumber; + } + + public void setBNumber(String bNumber) { + this.bNumber = bNumber; + } + + @Override + public String toString() { + return "LongestPrefixMatchExampleCode{" + + "aNumber='" + aNumber + '\'' + + ", bNumber='" + bNumber + '\'' + + ", bValidFrom=" + bValidFrom + + ", cValidTo=" + cValidTo + + ", dResult='" + dResult + '\'' + + '}'; + } +} diff --git a/code/src/test/java/com/googlecode/cqengine/functional/IndexOrderingTest.java b/code/src/test/java/com/googlecode/cqengine/functional/IndexOrderingTest.java index f6ebb005e..e7339ddb1 100644 --- a/code/src/test/java/com/googlecode/cqengine/functional/IndexOrderingTest.java +++ b/code/src/test/java/com/googlecode/cqengine/functional/IndexOrderingTest.java @@ -38,8 +38,8 @@ public class IndexOrderingTest { public static void main(String[] args) { final int NUM_ITERATIONS = 1000; - final int[] numObjects = {10000, 10000, 100000}; - final double[] selectivityThreshold = {0.0, 0.5, 1.0}; + final int[] numObjects = {10000}; + final double[] selectivityThreshold = {1.0}; IndexedCollection cars = new ConcurrentIndexedCollection(); cars.addAll(CarFactory.createCollectionOfCars(1000000));