/** * Copyright 2012 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 * * * 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. */
import com.googlecode.cqengine.CQEngine;import com.googlecode.cqengine.IndexedCollection;import com.googlecode.cqengine.index.navigable.NavigableIndex;import com.googlecode.cqengine.index.radixreversed.ReversedRadixTreeIndex;import com.googlecode.cqengine.index.suffix.SuffixTreeIndex;import com.googlecode.cqengine.query.Query;import com.googlecode.cqengine.query.option.DeduplicationStrategy;import com.googlecode.cqengine.query.option.QueryOption;
import java.util.LinkedHashSet;import java.util.Set;import java.util.concurrent.TimeUnit;
import static com.googlecode.cqengine.query.QueryFactory.*;/** * An introductory example which demonstrates usage using a Car analogy. * * @author Niall Gallagher */public class CarBenchmark { public static Set<CarBenchObj> createCollectionOfCars(int numCars) { Set<CarBenchObj> cars = new LinkedHashSet<CarBenchObj>(numCars); for (int carId = 0; carId < numCars; carId++) { String uniqueName = "car"+carId; switch (carId % 10) { case 0: cars.add( new CarBenchObj(carId, "Ford", uniqueName, CarBenchObj.Color.RED, 5, 5000.00) ); break; case 1: cars.add( new CarBenchObj(carId, "Ford", uniqueName, CarBenchObj.Color.RED, 4, 3999.99) ); break; case 2: cars.add( new CarBenchObj(carId, "Ford", uniqueName, CarBenchObj.Color.GREEN, 4, 6000.00) ); break; case 3: cars.add( new CarBenchObj(carId, "Honda", uniqueName, CarBenchObj.Color.WHITE, 5, 4000.00) ); break; case 4: cars.add( new CarBenchObj(carId, "Honda", uniqueName, CarBenchObj.Color.BLACK, 5, 3000.00) ); break; case 5: cars.add( new CarBenchObj(carId, "Honda", uniqueName, CarBenchObj.Color.GREEN, 3, 5000.00) ); break; case 6: cars.add( new CarBenchObj(carId, "Toyota", uniqueName, CarBenchObj.Color.GREEN, 5, 5999.95) ); break; case 7: cars.add( new CarBenchObj(carId, "Toyota", uniqueName, CarBenchObj.Color.BLUE, 3, 8500.00) ); break; case 8: cars.add( new CarBenchObj(carId, "Toyota", uniqueName, CarBenchObj.Color.RED, 5, 7800.55) ); break; case 9: cars.add( new CarBenchObj(carId, "BMW", uniqueName, CarBenchObj.Color.BLUE, 2, 9000.23) ); break; default: throw new IllegalStateException(); } } return cars; }
public static void main(String[] args) { // Create an indexed collection (note: could alternatively use CQEngine.copyFrom() existing collection)... IndexedCollection<CarBenchObj> cars = CQEngine.newInstance();
// Add some indexes... cars.addIndex(NavigableIndex.onAttribute(CarBenchObj.CAR_ID)); cars.addIndex(NavigableIndex.onAttribute(CarBenchObj.MODEL)); cars.addIndex(NavigableIndex.onAttribute(CarBenchObj.MANUFACTURER)); cars.addIndex(NavigableIndex.onAttribute(CarBenchObj.TESTVAL)); cars.addAll(createCollectionOfCars(10)); Query<CarBenchObj> query = equal(CarBenchObj.TESTVAL, false); // Prints True System.out.println(cars.retrieve(query).size() == 10); CarBenchObj testCar = new CarBenchObj(10, "BMW", "car11", CarBenchObj.Color.BLUE, 2, 9000.23); cars.add(testCar); // Prints True System.out.println(cars.retrieve(query).size() == 11); System.out.println(cars.retrieve(equal(CarBenchObj.TESTVAL, true)).size() == 0); // modify object testCar.setTestVal(true); // Prints True, object removed System.out.println(cars.remove(testCar)); // Still prints true, should be 10 System.out.println(cars.retrieve(query).size() == 11); // Car Object ID #10 still exist for(CarBenchObj car:cars.retrieve(query)) { System.out.println(car.getCarId()); } // Prints true, total is only 10 System.out.println(cars.size() == 10); QueryOption<CarBenchObj> deduplication = deduplicate(DeduplicationStrategy.MATERIALIZE); // Still prints true, should be 10 System.out.println(cars.retrieve(query,queryOptions(deduplication)).size() == 11);
}}import com.googlecode.cqengine.attribute.Attribute;import com.googlecode.cqengine.attribute.SimpleAttribute;
/** * @author Niall Gallagher */public class CarBenchObj {
public static final Attribute<CarBenchObj, Integer> CAR_ID = new SimpleAttribute<CarBenchObj, Integer>("carId") { @Override public Integer getValue(CarBenchObj car) { return car.carId; } };
public static final Attribute<CarBenchObj, String> MANUFACTURER = new SimpleAttribute<CarBenchObj, String>("manufacturer") { @Override public String getValue(CarBenchObj car) { return car.manufacturer; } };
public static final Attribute<CarBenchObj, String> MODEL = new SimpleAttribute<CarBenchObj, String>("model") { @Override public String getValue(CarBenchObj car) { return car.model; } };
public static final Attribute<CarBenchObj, Color> COLOR = new SimpleAttribute<CarBenchObj, Color>("color") { @Override public Color getValue(CarBenchObj car) { return car.color; } };
public static final Attribute<CarBenchObj, Integer> DOORS = new SimpleAttribute<CarBenchObj, Integer>("doors") { @Override public Integer getValue(CarBenchObj car) { return car.doors; } };
public static final Attribute<CarBenchObj, Double> PRICE = new SimpleAttribute<CarBenchObj, Double>("price") { @Override public Double getValue(CarBenchObj car) { return car.price; } }; public static final Attribute<CarBenchObj, Boolean> TESTVAL = new SimpleAttribute<CarBenchObj, Boolean>("testVal") { @Override public Boolean getValue(CarBenchObj car) { return car.testVal; } };
public enum Color {RED, GREEN, BLUE, BLACK, WHITE} private final int carId; private final String manufacturer; private final String model; private final Color color; private final int doors; private final double price; private boolean testVal = false;
public CarBenchObj(int carId, String manufacturer, String model, Color color, int doors, double price) { this.carId = carId; this.manufacturer = manufacturer; this.model = model; this.color = color; this.doors = doors; this.price = price; }
public int getCarId() { return carId; }
public String getManufacturer() { return manufacturer; }
public String getModel() { return model; }
public Color getColor() { return color; }
public int getDoors() { return doors; }
public double getPrice() { return price; }
@Override public String toString() { return "Car{" + "carId=" + carId + ", manufacturer='" + manufacturer + '\'' + ", model='" + model + '\'' + ", color=" + color + ", doors=" + doors + ", price=" + price + '}'; }
@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false;
CarBenchObj car = (CarBenchObj) o;
if (carId != car.carId) return false;
return true; }
@Override public int hashCode() { return carId; }
public boolean isTestVal() { return testVal; }
public void setTestVal(boolean testVal) { this.testVal = testVal; } }--
-- You received this message because you are subscribed to the "cqengine-discuss" group.
http://groups.google.com/group/cqengine-discuss
---
You received this message because you are subscribed to the Google Groups "cqengine-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cqengine-discu...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
@Override public void notifyObjectsRemoved(Collection<O> objects) { ConcurrentMap<A, StoredResultSet<O>> indexMap = this.indexMap; for (O object : objects) { Iterable<A> attributeValues = getAttribute().getValues(object); for (A attributeValue : attributeValues) { Iterator<Entry<A, StoredResultSet<O>>> it = indexMap.entrySet().iterator(); while(it.hasNext()) { Entry<A, StoredResultSet<O>> entry = it.next(); StoredResultSet<O> valueSet = entry.getValue(); if(valueSet.contains(object)) { System.out.println("Found object"); valueSet.remove(object); if (valueSet.isEmpty()) { indexMap.remove(attributeValue); } } } } /* Iterable<A> attributeValues = getAttribute().getValues(object); for (A attributeValue : attributeValues) {
// Replace attributeValue with quantized value if applicable... attributeValue = getQuantizedValue(attributeValue);
StoredResultSet<O> valueSet = indexMap.get(attributeValue); if (valueSet == null) { continue; } valueSet.remove(object); if (valueSet.isEmpty()) { indexMap.remove(attributeValue); } }*/ } }--
import java.util.Collection;import java.util.Map.Entry;import java.util.Set;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.ConcurrentMap;import java.util.concurrent.ConcurrentNavigableMap;
import com.googlecode.cqengine.attribute.Attribute;import com.googlecode.cqengine.attribute.SimpleAttribute;import com.googlecode.cqengine.index.common.Factory;import com.googlecode.cqengine.index.navigable.NavigableIndex;import com.googlecode.cqengine.resultset.stored.StoredResultSet;
public class MyNavigableIndex<A extends Comparable<A>, O> extends NavigableIndex<A, O> {
protected MyNavigableIndex(Factory<ConcurrentNavigableMap<A, StoredResultSet<O>>> indexMapFactory, Factory<StoredResultSet<O>> valueSetFactory, Attribute<O, A> attribute) { super(indexMapFactory, valueSetFactory, attribute); }
// ---------- Static factory methods to create NavigableIndexes ----------
/** * Creates a new {@code NavigableIndex} on the given attribute. The attribute can be a {@link SimpleAttribute} or a * {@link com.googlecode.cqengine.attribute.MultiValueAttribute}, as long as the type of the attribute referenced * implements {@link Comparable}. * <p/> * @param attribute The attribute on which the index will be built, a {@link SimpleAttribute} or a * {@link com.googlecode.cqengine.attribute.MultiValueAttribute} where the type of the attribute referenced * implements {@link Comparable} * @param <A> The type of the attribute * @param <O> The type of the object containing the attribute * @return A new HashIndex which will build an index on this attribute */ public static <A extends Comparable<A>, O> NavigableIndex<A, O> onAttribute(Attribute<O, A> attribute) { return onAttribute(new DefaultIndexMapFactory<A, O>(), new DefaultValueSetFactory<O>(), attribute); } public static <A extends Comparable<A>, O> NavigableIndex<A, O> onAttribute(Factory<ConcurrentNavigableMap<A, StoredResultSet<O>>> indexMapFactory, Factory<StoredResultSet<O>> valueSetFactory, Attribute<O, A> attribute) { return new MyNavigableIndex<A, O>(indexMapFactory, valueSetFactory, attribute); } private ConcurrentHashMap<O, ObjectIndex> objectIndexMap = new ConcurrentHashMap<O, ObjectIndex>(); class ObjectIndex { private ConcurrentHashMap<A, StoredResultSet<O>> valueSets = new ConcurrentHashMap<A, StoredResultSet<O>>(); public ConcurrentHashMap<A, StoredResultSet<O>> getValueSets() { return valueSets; } } /** * {@inheritDoc} */ @Override public void notifyObjectsAdded(Collection<O> objects) { ConcurrentMap<A, StoredResultSet<O>> indexMap = this.indexMap; for (O object : objects) { Iterable<A> attributeValues = getAttribute().getValues(object); for (A attributeValue : attributeValues) {
// Replace attributeValue with quantized value if applicable... attributeValue = getQuantizedValue(attributeValue);
// Look up StoredResultSet for the value... StoredResultSet<O> valueSet = indexMap.get(attributeValue); if (valueSet == null) { // No StoredResultSet, create and add one... valueSet = valueSetFactory.create(); StoredResultSet<O> existingValueSet = indexMap.putIfAbsent(attributeValue, valueSet); if (existingValueSet != null) { // Another thread won race to add new value set, use that one... valueSet = existingValueSet; } } // Add the object to the StoredResultSet for this value... valueSet.add(object); // Add reverse Lookup ObjectIndex oi = objectIndexMap.get(object); if(oi == null) { oi = new ObjectIndex(); objectIndexMap.put(object, oi); }
oi.getValueSets().put(attributeValue, valueSet); } } } /** * {@inheritDoc} */ public void notifyObjectsRemoved(Collection<O> objects) { ConcurrentMap<A, StoredResultSet<O>> indexMap = this.indexMap; for (O object : objects) { ObjectIndex oi = objectIndexMap.get(object); if(oi != null) { Set<Entry<A, StoredResultSet<O>>> valueSets = oi.getValueSets().entrySet(); for (Entry<A, StoredResultSet<O>> entry : valueSets) { StoredResultSet<O> valueSet = entry.getValue(); valueSet.remove(object); if (valueSet.isEmpty()) { indexMap.remove(entry.getKey()); } }
oi.getValueSets().clear(); objectIndexMap.remove(object); } } }
}
So my understanding of how you were planning to work around this, was that you would create a backup of the attribute values at the point when the object is first added to the index, and store those in a reverse lookup map.Then when trying to remove the object, you would not ask the attribute to provide the values again, you would just look them up in your reverse lookup map.So I thought that your reverse lookup map would simply be:Map<O, List<A>> // map of Object, to list of the values it has for the attribute.
Ok I think I understand. That would work, but I guess might leave some empty StoredResultSets in the index.
Currently it also removes empty StoredResultSets, so you might want to do that too.
Sent from my Android
--
--
-- You received this message because you are subscribed to the "cqengine-discuss" group.
http://groups.google.com/group/cqengine-discuss
---
You received this message because you are subscribed to the Google Groups "cqengine-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cqengine-discuss+unsubscribe@googlegroups.com.
To unsubscribe from this group and stop receiving emails from it, send an email to cqengine-discu...@googlegroups.com.