package org.aksw.sparqlify.database;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
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;
interface MapStoreAccessor {
//void add(Object store, List<?> row);
//void put(Object store, Object )
Set<Class<?>> getSupportedConstraintClasses();
//
// Insertion and lookup of rows
//
void put(Object store, List<?> row, Object value);
Object get(Object store, List<Object> row);
// TODO: Is this the same as lookup without constraints? Guess so!
Collection<Object> list(Object store);
//
// Lookup with constraints (e.g. greater(1.0), equals('foo'), ...
//
Collection<Object> lookup(Object store, Constraint constraint);
/**
* Create a new store that can be used with this accessor
*
* @return
*/
Object createStore();
}
interface IndexStore {
public List<Object> lookup(List<Constraint> constraints);
}
/**
* Accessor for a NavigableMap<List<?>, Object>
*
* We separate the accessor from the store, in order to avoid duplicating
* (referenences to) the index metadata at each node of the index tree -
* this way there is just one accessor with the metadata, which can
* work on any corresponding store at some level in an hierarchical index.
*
*
* @author Claus Stadler <cstadler@informatik.uni-leipzig.de>
*
*/
public class PrefixMapStoreAccessor
implements MapStoreAccessor
{
public static Set<Class<?>> supportedConstraintClasses = new HashSet<Class<?>>();
static
{
supportedConstraintClasses.add(EqualsConstraint.class);
supportedConstraintClasses.add(StartsWithConstraint.class);
supportedConstraintClasses.add(IsPrefixOfConstraint.class);
}
public Set<Class<?>> getSupportedConstraintClasses() {
return supportedConstraintClasses;
}
private int indexColumn;
private Transformer<Object, Set<String>> prefixExtractor;
public PrefixMapStoreAccessor(int[] indexColumns, Transformer<Object, Set<String>> prefixExtractor) {
if(indexColumns.length != 1) {
throw new RuntimeException("Prefix index can only operate on single columns");
}
this.indexColumn = indexColumns[0];
this.prefixExtractor = prefixExtractor;
}
/**
* We assume that
* . only classes that are in supportedConstraintClasses are passed to this method.
* . only constraints for which the index has the right columns are passed
*
* This method should only be used by the engine
*
* @param constraints
* @return
*/
/*
@Override
public Collection<Object> lookup(Object store, List<Constraint> constraints)
{
return lookup((NavigableMap<String, Object>)store, constraints);
}*/
@Override
public void put(Object store, List<?> row, Object value) {
/*
PatriciaTrie<String, Integer> x;
x.prefixMap(arg0)
*/
put((NavigableMap<String, Object>)store, row, value);
}
public void put(NavigableMap<String, Object> map, List<?> row, Object value) {
map.put((String)row.get(indexColumn), value);
}
///*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 Collection<Object> lookup(Object store, Constraint constraint) {
NavigableMap<String, Object> map = (NavigableMap<String, Object>)store;
if(constraint instanceof IsPrefixOfConstraint) {
return lookup(map, (IsPrefixOfConstraint)constraint);
} else if(constraint instanceof StartsWithConstraint) {
return lookup(map, (StartsWithConstraint)constraint);
} else if(constraint instanceof EqualsConstraint) {
return lookup(map, (EqualsConstraint)constraint);
} else {
throw new RuntimeException("Could not handle constraint " + constraint);
}
}
public Collection<Object> lookup(NavigableMap<String, Object> map, EqualsConstraint constraint) {
return Collections.singleton(map.get(constraint.getValue()));
}
public Collection<Object> lookup(NavigableMap<String, Object> map, StartsWithConstraint constraint) {
return StringUtils.getAllPrefixedEntries(constraint.getPrefix(), constraint.isInclusive(), map).values();
}
public Collection<Object> lookup(NavigableMap<String, Object> map, IsPrefixOfConstraint constraint) {
return StringUtils.getAllPrefixes(constraint.getValue(), constraint.isInclusive(), map).values();
}
@Override
public Object get(Object store, List<Object> row) {
return get((NavigableMap<String, Object>)store, row);
}
public Object get(NavigableMap<String, Object> map, List<Object> row) {
return map.get(row.get(indexColumn));
}
@SuppressWarnings("unchecked")
@Override
public Collection<Object> list(Object store) {
return ((NavigableMap<String, Object>)store).values();
}
@Override
public Object createStore() {
return new TreeMap<String, Object>();
}
/*
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, 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.getAllPrefixes(prefix, true, current);
for(Entry<String, Object> entry : candidates.entrySet()) {
NavigableMap<String, Object> next = (NavigableMap<String, Object>) 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(NavigableMap<String, Object> current, int i, Collection<List<T>> result) {
// Add everything that is left
boolean isLast = i == indexColumns.length - 1;
int index = indexColumns[i];
if(isLast) {
for(Object o : current.values()) {
List<T> row = (List<T>) o;
result.add(row);
}
} else {
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);
}
}
}
*/
}