@Test public void testAnyOnArrayLiteral() throws Exception { Reference ref = createReference("d", DataTypes.STRING); Literal stringArrayLiteral = Literal.newLiteral( new Object[] {new BytesRef("a"), new BytesRef("b"), new BytesRef("c")}, new ArrayType(DataTypes.STRING)); // col != ANY (1,2,3) Query neqQuery = convert(whereClause(AnyNeqOperator.NAME, ref, stringArrayLiteral)); assertThat(neqQuery, instanceOf(FilteredQuery.class)); assertThat(((FilteredQuery) neqQuery).getFilter(), instanceOf(BooleanFilter.class)); BooleanFilter filter = (BooleanFilter) ((FilteredQuery) neqQuery).getFilter(); assertThat(filter.toString(), is("BooleanFilter(-BooleanFilter(+d:a +d:b +d:c))")); // col like any (1,2,3) Query likeQuery = convert(whereClause(AnyLikeOperator.NAME, ref, stringArrayLiteral)); assertThat(likeQuery, instanceOf(BooleanQuery.class)); BooleanQuery likeBQuery = (BooleanQuery) likeQuery; assertThat(likeBQuery.clauses().size(), is(3)); for (int i = 0; i < 2; i++) { // like --> XConstantScoreQuery with regexp-filter Query filteredQuery = likeBQuery.clauses().get(i).getQuery(); assertThat(filteredQuery, instanceOf(XConstantScoreQuery.class)); assertThat(((XConstantScoreQuery) filteredQuery).getFilter(), instanceOf(RegexpFilter.class)); } // col not like any (1,2,3) Query notLikeQuery = convert(whereClause(AnyNotLikeOperator.NAME, ref, stringArrayLiteral)); assertThat(notLikeQuery, instanceOf(BooleanQuery.class)); BooleanQuery notLikeBQuery = (BooleanQuery) notLikeQuery; assertThat(notLikeBQuery.clauses(), hasSize(1)); BooleanClause clause = notLikeBQuery.clauses().get(0); assertThat(clause.getOccur(), is(BooleanClause.Occur.MUST_NOT)); assertThat(((BooleanQuery) clause.getQuery()).clauses(), hasSize(3)); for (BooleanClause innerClause : ((BooleanQuery) clause.getQuery()).clauses()) { assertThat(innerClause.getOccur(), is(BooleanClause.Occur.MUST)); assertThat(innerClause.getQuery(), instanceOf(XConstantScoreQuery.class)); assertThat( ((XConstantScoreQuery) innerClause.getQuery()).getFilter(), instanceOf(RegexpFilter.class)); } // col < any (1,2,3) Query ltQuery2 = convert(whereClause(AnyLtOperator.NAME, ref, stringArrayLiteral)); assertThat(ltQuery2, instanceOf(BooleanQuery.class)); BooleanQuery ltBQuery = (BooleanQuery) ltQuery2; assertThat(ltBQuery.toString(), is("(d:{* TO a} d:{* TO b} d:{* TO c})~1")); }
@Override protected Query applyArrayLiteral(Reference reference, Literal arrayLiteral, Context context) throws IOException { // col != ANY ([1,2,3]) --> not(col=1 and col=2 and col=3) String columnName = reference.info().ident().columnIdent().fqn(); QueryBuilderHelper builder = QueryBuilderHelper.forType(reference.valueType()); BooleanFilter filter = new BooleanFilter(); BooleanFilter notFilter = new BooleanFilter(); for (Object value : toIterable(arrayLiteral.value())) { notFilter.add(builder.eqFilter(columnName, value), BooleanClause.Occur.MUST); } filter.add(notFilter, BooleanClause.Occur.MUST_NOT); return new FilteredQuery(Queries.newMatchAllQuery(), filter); }
@Override public Query apply(Function input, Context context) { assert input != null; assert input.arguments().size() == 1; Symbol arg = input.arguments().get(0); if (arg.symbolType() != SymbolType.REFERENCE) { return null; } Reference reference = (Reference) arg; String columnName = reference.info().ident().columnIdent().fqn(); QueryBuilderHelper builderHelper = QueryBuilderHelper.forType(reference.valueType()); BooleanFilter boolFilter = new BooleanFilter(); boolFilter.add( builderHelper.rangeFilter(columnName, null, null, true, true), BooleanClause.Occur.MUST_NOT); return new FilteredQuery(Queries.newMatchAllQuery(), boolFilter); }
@Override public Query apply(Function input, Context context) { Tuple<Reference, Literal> tuple = super.prepare(input); if (tuple == null) { return null; } Reference reference = tuple.v1(); Literal literal = tuple.v2(); String columnName = reference.info().ident().columnIdent().fqn(); if (DataTypes.isCollectionType(reference.valueType()) && DataTypes.isCollectionType(literal.valueType())) { // create boolean filter with term filters to pre-filter the result before applying the // functionQuery. BooleanFilter boolTermsFilter = new BooleanFilter(); DataType type = literal.valueType(); while (DataTypes.isCollectionType(type)) { type = ((CollectionType) type).innerType(); } QueryBuilderHelper builder = QueryBuilderHelper.forType(type); Object value = literal.value(); buildTermsQuery(boolTermsFilter, value, columnName, builder); if (boolTermsFilter.clauses().isEmpty()) { // all values are null... return genericFunctionQuery(input, context); } // wrap boolTermsFilter and genericFunction filter in an additional BooleanFilter to // control the ordering of the filters // termsFilter is applied first // afterwards the more expensive genericFunctionFilter BooleanFilter filterClauses = new BooleanFilter(); filterClauses.add(boolTermsFilter, BooleanClause.Occur.MUST); filterClauses.add(genericFunctionFilter(input, context), BooleanClause.Occur.MUST); return new FilteredQuery(Queries.newMatchAllQuery(), filterClauses); } QueryBuilderHelper builder = QueryBuilderHelper.forType(tuple.v1().valueType()); return builder.eq(columnName, tuple.v2().value()); }
@Test public void testEqOnTwoArraysBecomesGenericFunctionQuery() throws Exception { DataType longArray = new ArrayType(DataTypes.LONG); Query query = convert( new WhereClause( createFunction( EqOperator.NAME, DataTypes.BOOLEAN, createReference("x", longArray), Literal.newLiteral(longArray, new Object[] {10L, null, 20L})))); assertThat(query, instanceOf(FilteredQuery.class)); FilteredQuery filteredQuery = (FilteredQuery) query; assertThat(filteredQuery.getFilter(), instanceOf(BooleanFilter.class)); assertThat(filteredQuery.getQuery(), instanceOf(XConstantScoreQuery.class)); BooleanFilter filter = (BooleanFilter) filteredQuery.getFilter(); assertThat( filter.clauses().get(0).getFilter(), instanceOf(BooleanFilter.class)); // booleanFilter with terms filter assertThat( filter.clauses().get(1).getFilter(), instanceOf(Filter.class)); // generic function filter }
private void buildTermsQuery( BooleanFilter booleanFilter, Object value, String columnName, QueryBuilderHelper builder) { if (value == null) { return; } if (value.getClass().isArray()) { Object[] array = (Object[]) value; for (Object o : array) { buildTermsQuery(booleanFilter, o, columnName, builder); } } else { booleanFilter.add(builder.eqFilter(columnName, value), BooleanClause.Occur.MUST); } }