mirror of
https://github.com/querydsl/querydsl.git
synced 2026-06-16 21:01:10 +08:00
added index creation to DefaultIndexSupport
This commit is contained in:
parent
1ac5643811
commit
a691050077
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@ -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) {
|
||||
|
||||
@ -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('%');
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user