package org.aksw.sparqlify.database; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.NavigableMap; import java.util.Set; import java.util.TreeMap; import org.aksw.commons.util.strings.StringUtils; import org.apache.commons.collections15.Transformer; import com.google.common.collect.Sets; interface PrefixIndexValue { } enum LookupDirection { SHORTER, LONGER, BOTH; } public class PrefixIndex<T> implements Index<T> { // The table this index is bound to private Table<T> table; private int[] indexColumns; private List<String> indexColumnNames; private Transformer<T, Set<String>> prefixExtractor; private NavigableMap<String, Object> map = new TreeMap<String, Object>(); public PrefixIndex(Table<T> table, int[] indexColumns, Transformer<T, Set<String>> prefixExtractor) { this.table = table; this.indexColumns = indexColumns; this.prefixExtractor = prefixExtractor; this.indexColumnNames = new ArrayList<String>(); for(int index : indexColumns) { this.indexColumnNames.add(table.getColumns().getKey(index)); } } //private Transformer<T, String> transformer; public void index(String ... row) { } @Override public void add(List<? extends T> row) { NavigableMap<String, Object> current = map; for(int i = 0; i < indexColumns.length; ++i) { boolean isLast = i == indexColumns.length - 1; int index = indexColumns[i]; T value = row.get(index); Set<String> prefixes = prefixExtractor.transform(value); for(String prefix : prefixes) { Object o = current.get(prefix); if(isLast) { Set<Object> values = (Set<Object>)o; if(values == null) { values = new HashSet<Object>(); current.put(prefix, values); } /* else { throw new RuntimeException("Duplicate row"); }*/ values.add(row); } else { NavigableMap<String, Object> next = (NavigableMap<String, Object>) o; if(next == null) { next = new TreeMap<String, Object>(); current.put(prefix, next); } current = next; } } } } ///*protected PrefixMap<PrefixIndexElement> /** * The constraints given as arguments are interpreted as conjunctions. * The set of prefixes within a constraint is interpreted as a disjunction. * * * @param constraints */ public void lookup(Constraint ... constraints) { /* for(VariableConstraintPrefix constraint : constraints) { String columnName = constraint.getVariableName(); }*/ } public Collection<List<T>> lookupSimple(List<String> prefixList) { List<List<T>> result = new ArrayList<List<T>>(); lookupSimple(prefixList, 0, map, result); return result; } public Collection<List<T>> lookupSimpleLonger(List<String> prefixList) { List<List<T>> result = new ArrayList<List<T>>(); lookupSimpleLonger(prefixList, 0, map, result); return result; } public void lookupSimple(List<String> prefixList, int i, Object tmp, Collection<List<T>> result) { boolean isLast = i == prefixList.size(); //Entry<String, Object> o; if(isLast) { lookupRemaining(tmp, i, result); } else { NavigableMap<String, Object> current = (NavigableMap<String, Object>)tmp; //int index = indexColumns[i]; String prefix = prefixList.get(i); Map<String, Object> candidates = StringUtils.getAllPrefixes(prefix, true, current); for(Entry<String, Object> entry : candidates.entrySet()) { Object next = entry.getValue(); lookupSimple(prefixList, i + 1, next, result); } } } public void lookupSimpleLonger(List<String> prefixList, int i, NavigableMap<String, Object> current, Collection<List<T>> result) { boolean isLast = i == prefixList.size(); //Entry<String, Object> o; if(isLast) { lookupRemaining(current, i, result); } else { int index = indexColumns[i]; String prefix = prefixList.get(index); Map<String, Object> candidates = StringUtils.getAllPrefixedEntries(prefix, true, current); for(Entry<String, Object> entry : candidates.entrySet()) { NavigableMap<String, Object> next = (NavigableMap<String, Object>) entry.getValue(); lookupSimpleLonger(prefixList, i + 1, next, result); } } } public void lookupRemaining(Object tmp, int i, Collection<List<T>> result) { // Add everything that is left boolean isLast = i == indexColumns.length - 1; int index = indexColumns[i]; if(isLast) { Set<List<T>> current = (Set<List<T>>)tmp; result.addAll(current); /* for(Object o : current) { Set<List<T>> rows = (Set<List<T>>) o; //List<T> row = (List<T>) o; result.addAll(rows); }*/ } else { NavigableMap<String, Object> current = (NavigableMap<String, Object>)tmp; for(Object o : current.values()) { NavigableMap<String, Object> next = (NavigableMap<String, Object>) o; lookupRemaining(next, i + 1, result); } } } public Collection<List<T>> lookup(List<Set<String>> prefixesList) { List<List<T>> result = new ArrayList<List<T>>(); lookup(prefixesList, 0, map, result); return result; } public void lookup(List<Set<String>> prefixesList, int i, NavigableMap<String, Object> current, Collection<List<T>> result) { boolean isLast = i == indexColumns.length - 1; int index = indexColumns[i]; Set<String> prefixes = prefixesList.get(index); for(String prefix : prefixes) { Object o = current.get(prefix); if(isLast) { if(o == null) { return; } List<T> row = (List<T>) o; result.add(row); } else { NavigableMap<String, Object> next = (NavigableMap<String, Object>) o; if(next == null) { return; } lookup(prefixesList, i + 1, next, result); } } } public static <T> PrefixIndex<T> attach(Transformer<T, Set<String>> prefixExtractor, Table<T> table, String ... columnNames) { List<String> names = Arrays.asList(columnNames); Set<String> nameSet = new HashSet<String>(names); Set<String> dangling = Sets.difference(nameSet, table.getColumns().keySet()); if(!dangling.isEmpty()) { throw new RuntimeException("Columns " + dangling + " referenced, but not present in table"); } int[] indexColumns = new int[columnNames.length]; for(int i = 0; i < columnNames.length; ++i) { Integer index = table.getColumns().getIndex(columnNames[i]); if(index == null) { throw new NullPointerException("Column name does not have an index"); } indexColumns[i] = index; } PrefixIndex<T> index = new PrefixIndex<T>(table, indexColumns, prefixExtractor); table.addIndex(index); return index; } @Override public boolean preAdd(List<? extends T> row) { return true; } @Override public void postAdd(List<? extends T> row) { } @Override public Table<T> getTable() { return table; } @Override public int[] getIndexColumns() { return indexColumns; } @Override public List<String> getIndexColumnNames() { return indexColumnNames; } @Override public String toString() { return "PrefixIndex [table=" + table + ", indexColumnNames=" + indexColumnNames + "]"; } @Override public IndexMetaNode getRoot() { // TODO Auto-generated method stub return null; } @Override public Object getStore() { // TODO Auto-generated method stub return null; } }