package org.space4j.examples.phonebook; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentNavigableMap; import org.space4j.Space4J; import org.space4j.implementation.SimpleSpace4J; import org.space4j.indexing.Index; import org.space4j.indexing.IndexManager; import org.space4j.indexing.Key; import org.space4j.indexing.MultiMap; import org.space4j.indexing.MultiSortedMap; public class PhoneBookIndexing extends PhoneBook { private static final String INDX_LASTNAME = "indx_lastname"; private static final String INDX_AGE = "indx_age"; private final Index indexByLastName; private final Index indexByAge; public PhoneBookIndexing(Space4J space4j) throws Exception { super(space4j); IndexManager im = space.getIndexManager(); // If index does not exist, let's create it... if (!im.checkIndex(INDX_LASTNAME)) { /* * Index name = INDX_LASTNAME * Map in the Space that will be indexed = MAP_NAME * Type of index = MULTI = non-unique index * Object that will be indexed = User.class * Atributes of the object that will be indexed = "lastName" * * We want to create this index because we will be searching * for Users by lastName. We don't want to do a full table * scan anymore like in the example without indexes. */ Index indx = new Index(INDX_LASTNAME, MAP_NAME, Index.TYPE.MULTI, User.class, "lastName"); boolean ok = im.createIndex(indx, space4j); if (ok) { System.out.println(indx + " created!"); } else { System.out.println(indx + " could not be created!"); } } // If index does not exist, let's create it... if (!im.checkIndex(INDX_AGE)) { /* * Index name = INDX_AGE * Map in the Space that will be indexed = MAP_NAME * Type of index = MULTI = non-unique sorted index * Object that will be indexed = User.class * Atributes of the object that will be indexed = "age" * * We want to create this index because we will be searching * for Users by age. The index will be SORTED because we want * to search for users in a age range. (age > min and age < max) */ Index indx = new Index(INDX_AGE, MAP_NAME, Index.TYPE.MULTI_SORTED, User.class, "age"); boolean ok = im.createIndex(indx, space4j); if (ok) { System.out.println(indx + " created!"); } else { System.out.println(indx + " could not be created!"); } } indexByLastName = im.getIndex(INDX_LASTNAME); indexByAge = im.getIndex(INDX_AGE); } /* * Let's override our search method to use our * index instead of doing a full table scan. */ @Override public Collection findUsers(String last) { // Remember that our index is of the type MULTI. // That's why we are doing this cast here. MultiMap map = (MultiMap) indexByLastName.getMap(); // A multi-map will store a Collection for each key. // That's why our index is NON-UNIQUE meaning the same // key can be associated with many entries in the map. // That makes sense as some users can have the same // last name. Collection coll = (Collection) map.get(last); return coll; } @Override public Collection findUsers(int minAge, int maxAge) { // Remember that our index is of the type MULTI_SORTED. // That's why we are doing this cast here. MultiSortedMap map = (MultiSortedMap) indexByAge.getMap(); // A multi-sorted-map will store a Map for each key. // That's why our index is NON-UNIQUE meaning the same // key can be associated with many entries in the map. // The map is also sorted by its key, meaning we can // perform range searches efficiently. ConcurrentNavigableMap subMap = map.subMap(new Key(minAge), true, new Key(maxAge), true); Collection users = new ArrayList(subMap.size() * 3); Iterator iter = subMap.values().iterator(); while(iter.hasNext()) { // our collection here is actually a ConcurrentHashMap! Map m = (Map) iter.next(); // this is not good as we are transversing the whole list twice! // TODO: Create custom iterator for MultiSortedMap to avoid this? Iterator iter2 = m.keySet().iterator(); while(iter2.hasNext()) { users.add(iter2.next()); } } return users; } public static void main(String[] args) throws Exception { PhoneBookIndexing book = new PhoneBookIndexing( new SimpleSpace4J("PhoneBook")); run(book); } }