added index creation to DefaultIndexSupport

This commit is contained in:
Timo Westkämper 2009-03-12 14:59:57 +00:00
parent 1ac5643811
commit a691050077
10 changed files with 251 additions and 24 deletions

View File

@ -93,6 +93,7 @@ public class AbstractColQuery<SubType extends AbstractColQuery<SubType>> {
@SuppressWarnings("unchecked")
public Iterable<Object[]> iterate(Expr<?> e1, Expr<?> e2, Expr<?>... rest) {
// TODO : move this code to querydsl-core
final Expr<?>[] full = asArray(new Expr[rest.length + 2], e1, e2, rest);
boolean oneType = true;
if (e1.getType().isAssignableFrom((e2.getType()))){
@ -243,7 +244,7 @@ public class AbstractColQuery<SubType extends AbstractColQuery<SubType>> {
case DEFAULT : // do nothing
}
}
indexSupport.init(sources, where.create());
indexSupport.init(ops, sources, where.create());
multiIt.init(indexSupport);
if (!wrapIterators && (where.create() != null)){
@ -256,7 +257,7 @@ public class AbstractColQuery<SubType extends AbstractColQuery<SubType>> {
protected Iterator<?> handleFromWhereSingleSource(List<Expr<?>> sources) throws Exception{
JoinExpression<?> join = joins.get(0);
sources.add(join.getTarget());
indexSupport.init(sources, where.create());
indexSupport.init(ops, sources, where.create());
// create a simple projecting iterator for Object -> Object[]
Iterator<?> it = QueryIteratorUtils.toArrayIterator(indexSupport.getIterator(join.getTarget()));
@ -289,7 +290,7 @@ public class AbstractColQuery<SubType extends AbstractColQuery<SubType>> {
}
protected <RT> Iterator<RT> handleSelect(Iterator<?> it, List<Expr<?>> sources, Expr<RT> projection) throws Exception {
return QueryIteratorUtils.project(ops, it, sources, projection);
return QueryIteratorUtils.transform(ops, it, sources, projection);
}
public <RT> Iterable<RT> iterate(final Expr<RT> projection) {

View File

@ -8,6 +8,8 @@ package com.mysema.query.collections;
import java.util.Iterator;
import java.util.List;
import com.mysema.query.collections.support.DefaultIndexSupport;
import com.mysema.query.grammar.JavaOps;
import com.mysema.query.grammar.types.Expr;
import com.mysema.query.grammar.types.Expr.EBoolean;
@ -22,7 +24,15 @@ import com.mysema.query.grammar.types.Expr.EBoolean;
*/
public interface IndexSupport {
void init(List<Expr<?>> orderedSources, EBoolean condition);
/**
* init the IndexSupport instance
* NOTE : this IndexSupport instance is stateful and needs to be query specific, not global
*
* @param ops
* @param orderedSources
* @param condition
*/
void init(JavaOps ops, List<? extends Expr<?>> orderedSources, EBoolean condition);
<A> Iterator<A> getIterator(Expr<A> expr);

View File

@ -22,6 +22,12 @@ import com.mysema.query.grammar.types.Expr.EBoolean;
*/
public interface SourceSortingSupport {
/**
* sort the given join sources using some optimization heuristics based on the given match condition
*
* @param joins
* @param condition
*/
void sortSources(List<JoinExpression<Object>> joins, EBoolean condition);
}

View File

@ -116,8 +116,8 @@ public class FilteringMultiIterator extends MultiIterator implements IndexSuppor
return this;
}
public void init(List<Expr<?>> orderedSources, EBoolean condition) {
indexSupport.init(orderedSources, condition);
public void init(JavaOps ops, List<? extends Expr<?>> orderedSources, EBoolean condition) {
indexSupport.init(ops, orderedSources, condition);
}
}

View File

@ -1,32 +1,45 @@
/*
* Copyright (c) 2009 Mysema Ltd.
* All rights reserved.
*
*/
package com.mysema.query.collections.support;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.codehaus.janino.ExpressionEvaluator;
import com.mysema.query.collections.IndexSupport;
import com.mysema.query.collections.utils.EvaluatorUtils;
import com.mysema.query.collections.utils.QueryIteratorUtils;
import com.mysema.query.grammar.JavaOps;
import com.mysema.query.grammar.Ops;
import com.mysema.query.grammar.types.Expr;
import com.mysema.query.grammar.types.Operation;
import com.mysema.query.grammar.types.Path;
import com.mysema.query.grammar.types.Expr.EBoolean;
import com.mysema.query.util.Assert;
/**
* DefaultIndexSupport is the default implementation of the IndexSupport interface
*
* @see IndexSupport
* ExtendedIndexSupport provides
*
* @author tiwe
* @version $Id$
*/
public class DefaultIndexSupport implements IndexSupport{
private JavaOps ops;
private List<? extends Expr<?>> sources;
// private EBoolean condition;
private final Map<Expr<?>,Iterable<?>> exprToIt;
final Map<Path<?>,Map<?,? extends Iterable<?>>> pathEqPathIndex;
public DefaultIndexSupport(Map<Expr<?>,Iterable<?>> exprToIt){
this.exprToIt = exprToIt;
this.exprToIt = Assert.notNull(exprToIt);
this.pathEqPathIndex = new HashMap<Path<?>,Map<?,? extends Iterable<?>>>();
}
@SuppressWarnings("unchecked")
@ -36,11 +49,47 @@ public class DefaultIndexSupport implements IndexSupport{
@SuppressWarnings("unchecked")
public <A> Iterator<A> getIterator(Expr<A> expr, Object[] bindings) {
// TODO : make use of the index when appropriate
return (Iterator<A>)exprToIt.get(expr).iterator();
}
public void init(List<Expr<?>> sources, EBoolean condition) {
// do nothing
}
public void init(JavaOps ops, List<? extends Expr<?>> sources, EBoolean condition) {
this.ops = Assert.notNull(ops);
this.sources = Assert.notNull(sources);
// this.condition = Assert.notNull(condition);
// populate the "path eq path" index
// TODO : make a decision when index usage is appropriate
if (condition instanceof Operation){
visitOperation((Operation<?,?>) condition);
}
// TODO : filter the sources, based on non-contextual parts of the condition
}
private void visitOperation(Operation<?,?> op) {
if (op.getOperator() == Ops.EQ_OBJECT || op.getOperator() == Ops.EQ_PRIMITIVE){
if (op.getArgs()[0] instanceof Path && op.getArgs()[1] instanceof Path){
Path<?> p1 = (Path<?>) op.getArgs()[0], p2 = (Path<?>) op.getArgs()[1];
int i1 = sources.indexOf(p1.getRoot());
int i2 = sources.indexOf(p2.getRoot());
if (i1 < i2){
indexPath(p2);
}else if (i1 > i2){
indexPath(p1);
}
}
}else{
for (Expr<?> e : op.getArgs()){
if (e instanceof Operation) visitOperation((Operation<?, ?>) e);
}
}
}
private void indexPath(Path<?> path) {
ExpressionEvaluator ev = EvaluatorUtils.create(ops, Collections.<Expr<?>>singletonList((Expr<?>)path.getRoot()), (Expr<?>)path);
Map<?,? extends Iterable<?>> map = QueryIteratorUtils.projectToMap(exprToIt.get(path.getRoot()).iterator(), ev);
pathEqPathIndex.put(path, map);
}
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2009 Mysema Ltd.
* All rights reserved.
*
*/
package com.mysema.query.collections.support;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.mysema.query.collections.IndexSupport;
import com.mysema.query.grammar.JavaOps;
import com.mysema.query.grammar.types.Expr;
import com.mysema.query.grammar.types.Expr.EBoolean;
/**
* DefaultIndexSupport is the default implementation of the IndexSupport interface
*
* @see IndexSupport
*
* @author tiwe
* @version $Id$
*/
public class SimpleIndexSupport implements IndexSupport{
private final Map<Expr<?>,Iterable<?>> exprToIt;
public SimpleIndexSupport(Map<Expr<?>,Iterable<?>> exprToIt){
this.exprToIt = exprToIt;
}
@SuppressWarnings("unchecked")
public <A> Iterator<A> getIterator(Expr<A> expr) {
return (Iterator<A>)exprToIt.get(expr).iterator();
}
@SuppressWarnings("unchecked")
public <A> Iterator<A> getIterator(Expr<A> expr, Object[] bindings) {
return (Iterator<A>)exprToIt.get(expr).iterator();
}
public void init(JavaOps ops, List<? extends Expr<?>> sources, EBoolean condition) {
// do nothing
}
}

View File

@ -6,8 +6,7 @@
package com.mysema.query.collections.utils;
import java.lang.reflect.InvocationTargetException;
import java.util.Iterator;
import java.util.List;
import java.util.*;
import org.apache.commons.collections15.IteratorUtils;
import org.apache.commons.collections15.Predicate;
@ -34,6 +33,16 @@ public class QueryIteratorUtils {
}
}
/**
* filter the given iterator using the given condition
*
* @param <S>
* @param ops
* @param source
* @param sources
* @param condition
* @return
*/
public static <S> Iterator<S> multiArgFilter(JavaOps ops, Iterator<S> source, List<Expr<?>> sources, EBoolean condition){
ExpressionEvaluator ev = EvaluatorUtils.create(ops, sources, condition);
return multiArgFilter(source, ev);
@ -47,19 +56,63 @@ public class QueryIteratorUtils {
});
}
public static <S,T> Iterator<T> project(JavaOps ops, Iterator<S> source, List<Expr<?>> sources, Expr<?> projection){
/**
* transform the given source iterator using the given projection expression
*
* @param <S>
* @param <T>
* @param ops
* @param source
* @param sources
* @param projection
* @return
*/
public static <S,T> Iterator<T> transform(JavaOps ops, Iterator<S> source, List<Expr<?>> sources, Expr<?> projection){
ExpressionEvaluator ev = EvaluatorUtils.create(ops, sources, projection);
return project(source, ev);
return transform(source, ev);
}
private static <S,T> Iterator<T> project(Iterator<S> source, final ExpressionEvaluator ev){
private static <S,T> Iterator<T> transform(Iterator<S> source, final ExpressionEvaluator ev){
return IteratorUtils.transformedIterator(source, new Transformer<S,T>(){
public T transform(S input) {
return QueryIteratorUtils.<T>evaluate(ev, (Object[])input);
}
});
}
/**
* project the given source iterator to a map by treating the iterator values
* as map values and the projections as map keys
*
* @param <S>
* @param <T>
* @param source
* @param ev
* @return
*/
public static <S,T> Map<S,? extends Iterable<T>> projectToMap(Iterator<S> source, ExpressionEvaluator ev){
Map<S,Collection<T>> map = new HashMap<S,Collection<T>>();
while (source.hasNext()){
S key = source.next();
T value = evaluate(ev, key);
Collection<T> col = map.get(key);
if (col == null){
col = new ArrayList<T>();
map.put(key, col);
}
col.add(value);
}
return map;
}
/**
* filter the given iterator using the given expressionevaluator that evaluates to true / false
*
* @param <S>
* @param source
* @param ev
* @return
*/
public static <S> Iterator<S> singleArgFilter(Iterator<S> source, final ExpressionEvaluator ev){
return IteratorUtils.filteredIterator(source, new Predicate<S>(){
public boolean evaluate(S object) {

View File

@ -208,6 +208,7 @@ public class JavaSerializer extends BaseSerializer<JavaSerializer>{
@Override
protected void visitOperation(Class<?> type, Op<?> operator, Expr<?>... args) {
if (operator.equals(Ops.LIKE)){
// optimize like matches to startsWith and endsWith, when possible
String right = args[1].toString();
if (!right.contains("_")){
int lastIndex = right.lastIndexOf('%');

View File

@ -14,6 +14,7 @@ import org.junit.Test;
import com.mysema.query.JoinExpression;
import com.mysema.query.collections.IndexSupport;
import com.mysema.query.collections.MiniApi;
import com.mysema.query.grammar.JavaOps;
import com.mysema.query.grammar.types.Expr;
import com.mysema.query.grammar.types.Expr.EBoolean;
import com.mysema.query.grammar.types.Expr.ENumber;
@ -60,7 +61,7 @@ public class MultiIteratorTest extends AbstractIteratorTest {
return getIterator(expr);
}
public void init(List<Expr<?>> sources, EBoolean where) {
public void init(JavaOps ops, List<? extends Expr<?>> sources, EBoolean where) {
// TODO Auto-generated method stub
}

View File

@ -0,0 +1,59 @@
package com.mysema.query.collections.support;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import com.mysema.query.collections.AbstractQueryTest;
import com.mysema.query.grammar.JavaOps;
import com.mysema.query.grammar.types.Expr;
/**
* DefaultIndexSupportTest provides
*
* @author tiwe
* @version $Id$
*/
public class DefaultIndexSupportTest extends AbstractQueryTest{
private JavaOps ops = new JavaOps();
private Map<Expr<?>,Iterable<?>> exprToIt = new HashMap<Expr<?>,Iterable<?>>();
private DefaultIndexSupport indexSupport;
@Before
public void before(){
exprToIt.put(cat, cats);
exprToIt.put(otherCat, cats);
indexSupport = new DefaultIndexSupport(exprToIt);
}
@Test
public void test1(){
indexSupport.init(ops, Arrays.asList(cat,otherCat), cat.name.eq(otherCat.name));
Map<?,? extends Iterable<?>> map = indexSupport.pathEqPathIndex.get(otherCat.name);
assertTrue("map was null or empty", map != null && !map.isEmpty());
assertEquals(4, map.size());
assertTrue(indexSupport.pathEqPathIndex.get(cat.name) == null);
}
@Test
public void test2(){
indexSupport.init(ops, Arrays.asList(otherCat,cat), cat.name.eq(otherCat.name));
Map<?,? extends Iterable<?>> map = indexSupport.pathEqPathIndex.get(cat.name);
assertTrue("map was null or empty", map != null && !map.isEmpty());
assertEquals(4, map.size());
assertTrue(indexSupport.pathEqPathIndex.get(otherCat.name) == null);
}
}