diff --git a/src/main/scala/com/foursquare/slashem/Optimize.scala b/src/main/scala/com/foursquare/slashem/Optimize.scala new file mode 100644 index 0000000..61f7b81 --- /dev/null +++ b/src/main/scala/com/foursquare/slashem/Optimize.scala @@ -0,0 +1,27 @@ +/* + * Applies some simple optimizations + */ +package com.foursquare.slashem + +import com.foursquare.slashem.Ast._ + +object Optimizer { + + def optimizeFilters(filters: List[AbstractClause]): List[AbstractClause] = { + filters.filter(f => { + f match { + //Remove all empty search clauses + case Clause("*",Splat(),true) => false + case Clause("_all",Splat(),true) => false + case _ => true + } + }) + } + def optimizeQuery(clause: AbstractClause): AbstractClause = { + clause + } + def optimizeBoosts(boostQueries: List[AbstractClause]): List[AbstractClause] = { + boostQueries + } + +} diff --git a/src/main/scala/com/foursquare/slashem/QueryBuilder.scala b/src/main/scala/com/foursquare/slashem/QueryBuilder.scala index 91e4317..dd21b35 100644 --- a/src/main/scala/com/foursquare/slashem/QueryBuilder.scala +++ b/src/main/scala/com/foursquare/slashem/QueryBuilder.scala @@ -365,6 +365,10 @@ case class QueryBuilder[M <: Record[M], Ord, Lim, MM <: MinimumMatchType, Y, H < () } + /* Optimize the QueryBuilder */ + def optimize() = { + this.copy(filters=Optimizer.optimizeFilters(filters)) + } /** Fetch the results with the limit of l. Can only be used on an unlimited * query */ diff --git a/src/test/scala/com/foursquare/slashem/ElasticQueryTest.scala b/src/test/scala/com/foursquare/slashem/ElasticQueryTest.scala index 82dac4e..829ec19 100644 --- a/src/test/scala/com/foursquare/slashem/ElasticQueryTest.scala +++ b/src/test/scala/com/foursquare/slashem/ElasticQueryTest.scala @@ -624,3 +624,6 @@ class ElasticQueryTest extends SpecsMatchers with ScalaCheckMatchers { } } + +object ElasticQueryTest extends ElasticQueryTest { +} diff --git a/src/test/scala/com/foursquare/slashem/OptimizeTest.scala b/src/test/scala/com/foursquare/slashem/OptimizeTest.scala new file mode 100644 index 0000000..4e42dbe --- /dev/null +++ b/src/test/scala/com/foursquare/slashem/OptimizeTest.scala @@ -0,0 +1,74 @@ +package com.foursquare.slashem +import com.foursquare.slashem._ + +import com.twitter.util.Duration + +import org.bson.types.ObjectId +import org.junit.Test +import org.junit._ + +import org.scalacheck._ +import org.scalacheck.Gen._ +import org.scalacheck.Arbitrary.arbitrary + +import org.specs.SpecsMatchers +import org.specs.matcher.ScalaCheckMatchers + +import org.elasticsearch.node.NodeBuilder._ +import org.elasticsearch.node.Node +import org.elasticsearch.client.Requests; +import org.elasticsearch.common.xcontent.XContentFactory._; + +import java.util.concurrent.TimeUnit +import java.util.UUID + +import scalaj.collection.Imports._ + +import com.twitter.util.{Duration, ExecutorServiceFuturePool, Future, FuturePool, FutureTask, Throw, TimeoutException} +import java.util.concurrent.{Executors, ExecutorService} + +class OptimizeTest extends SpecsMatchers with ScalaCheckMatchers { + + //We test this because the optimizer screwed this up once + @Test + def testTermFiltersOptimize { + val q = ESimplePanda where (_.hugenums contains 1L) filter(_.termsfield in List("termhit", "randomterm")) + val res1 = q fetch() + val res2 = q optimize() fetch() + Assert.assertEquals(res1.response.results.length, res2.response.results.length) + } + + @Test + def testTermFiltersMetallFilter { + val q = ESimpleGeoPanda where (_.name contains "ordertest") filter(_.metall any) + val q2 = ESimpleGeoPanda where (_.name contains "ordertest") + val res1 = q fetch() + val res2 = q optimize() fetch() + val res3 = q2 fetch() + Assert.assertEquals(res1.response.results.length, res2.response.results.length) + Assert.assertEquals(res1.response.results.length, res3.response.results.length) + Assert.assertEquals(q.optimize(),q2) + } + + @Test + def testProduceCorrectListfieldFilterAny { + val q = SVenueTest where (_.metall any) filter (_.metall any) + val optimizedQ = q.optimize() + val qp = q.meta.queryParams(optimizedQ).toList + Assert.assertEquals(qp.sortWith(_._1 > _._1), + List("q" -> "*:*", + "start" -> "0", + "rows" -> "10").sortWith(_._1 > _._1)) + } + + @Before + def esSetup { + ElasticQueryTest.hoboPrepIndex() + } + + @After + def esDone { + ElasticQueryTest.hoboDone() + } + +} diff --git a/src/test/scala/com/foursquare/slashem/QueryTest.scala b/src/test/scala/com/foursquare/slashem/QueryTest.scala index c7bc7c6..49ed903 100644 --- a/src/test/scala/com/foursquare/slashem/QueryTest.scala +++ b/src/test/scala/com/foursquare/slashem/QueryTest.scala @@ -99,7 +99,6 @@ class QueryTest extends SpecsMatchers with ScalaCheckMatchers { } - @Test def testProduceCorrectSimpleQueryStringContains { val q = SUserTest where (_.fullname contains "jon")