/** * Copyright 2011 Molindo GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package at.molindo.elastic.compass; import java.util.ArrayList; import java.util.List; import java.util.Locale; import org.compass.core.CompassQuery.SortDirection; import org.compass.core.CompassQuery.SortImplicitType; import org.compass.core.CompassQuery.SortPropertyType; import org.compass.core.engine.SearchEngine; import org.compass.core.engine.SearchEngineHits; import org.compass.core.engine.SearchEngineQuery; import org.compass.core.engine.SearchEngineQueryFilter; import org.elasticsearch.index.query.xcontent.QueryBuilders; import org.elasticsearch.index.query.xcontent.XContentQueryBuilder; import at.molindo.elastic.filter.Filter; import at.molindo.elastic.query.BooleanClause; import at.molindo.elastic.query.BooleanQuery; import at.molindo.elastic.query.BoostQuery; import at.molindo.elastic.query.SpanQuery; import at.molindo.elastic.query.Query; import at.molindo.elastic.query.SortField; import at.molindo.elastic.query.SortField.SortType; import at.molindo.elastic.query.TermQuery; import at.molindo.elastic.term.Term; /** * @author kimchy */ public class ElasticSearchEngineQuery implements SearchEngineQuery, Cloneable { public static class ElasticSearchEngineSpanQuery extends ElasticSearchEngineQuery implements SearchEngineSpanQuery { public ElasticSearchEngineSpanQuery(ElasticSearchEngineFactory searchEngineFactory, SpanQuery query) { super(searchEngineFactory, query); } public SpanQuery getSpanQuery() { return (SpanQuery) getQuery(); } @Override public void setQuery(Query query) { if (query instanceof SpanQuery == false) { throw new IllegalArgumentException("must be a SpanQuery, was " + query); } super.setQuery(query); } } public static class QueryHolder { private final Query query; private final boolean suggested; public QueryHolder(Query query) { this(query, false); } public QueryHolder(Query query, boolean suggested) { this.query = query; this.suggested = suggested; } public Query getQuery() { return query; } public boolean isSuggested() { return suggested; } } private final ElasticSearchEngineFactory searchEngineFactory; private ArrayList<SortField> sortFields = new ArrayList<SortField>(3); private String[] aliases; // private ElasticSearchEngineQueryFilter filter; private Query origQuery; private Query query; private String defaultSearchProperty; private boolean rewrite; private boolean suggested; private ElasticSearchEngineQueryFilter filter; public ElasticSearchEngineQuery(ElasticSearchEngineFactory searchEngineFactory, Query query) { this(searchEngineFactory, new QueryHolder(query)); } public ElasticSearchEngineQuery(ElasticSearchEngineFactory searchEngineFactory, QueryHolder query) { this(searchEngineFactory, query, searchEngineFactory.getElasticSettings() .getDefaultSearchPropery()); } public ElasticSearchEngineQuery(ElasticSearchEngineFactory searchEngineFactory, QueryHolder query, String defualtSearchProperty) { this.searchEngineFactory = searchEngineFactory; this.query = query.getQuery(); this.origQuery = query.getQuery(); this.suggested = query.isSuggested(); this.defaultSearchProperty = defualtSearchProperty; } public ElasticSearchEngineQuery addSort(String propertyName) { sortFields.add(new SortField(propertyName)); return this; } public ElasticSearchEngineQuery addSort(String propertyName, SortDirection direction) { sortFields.add(new SortField(propertyName, getSortReverse(direction))); return this; } public ElasticSearchEngineQuery addSort(String propertyName, SortPropertyType type) { sortFields.add(new SortField(propertyName, getSortType(type))); return this; } public ElasticSearchEngineQuery addSort(String propertyName, SortPropertyType type, SortDirection direction) { sortFields.add(new SortField(propertyName, getSortType(type), getSortReverse(direction))); return this; } public ElasticSearchEngineQuery addSort(SortImplicitType implicitType) { sortFields.add(new SortField(null, getImplicitSortField(implicitType))); return this; } public ElasticSearchEngineQuery addSort(SortImplicitType implicitType, SortDirection direction) { sortFields .add(new SortField(null, getImplicitSortField(implicitType), getSortReverse(direction))); return this; } public ElasticSearchEngineQuery addSort(String propertyName, Locale locale, SortDirection direction) { sortFields.add(new SortField(propertyName, locale, getSortReverse(direction))); return this; } public ElasticSearchEngineQuery addSort(String propertyName, Locale locale) { sortFields.add(new SortField(propertyName, locale)); return this; } public ElasticSearchEngineQuery addSort(SortField sortField) { sortFields.add(sortField); return this; } public List<SortField> getSorts() { return sortFields; } private SortType getImplicitSortField(SortImplicitType implicitType) { switch (implicitType) { case DOC: return SortField.SortType.DOC; case SCORE: return SortField.SortType.SCORE; default: throw new IllegalArgumentException("Faile to create lucene implicit type for [" + implicitType + "]"); } } private boolean getSortReverse(SortDirection direction) { return direction == SortDirection.REVERSE; } private SortType getSortType(SortPropertyType type) { switch (type) { case AUTO: return SortField.SortType.SCORE; default: return SortField.SortType.FIELD; } } public SearchEngineHits hits(SearchEngine searchEngine) { return ((ElasticSearchEngine) searchEngine).find(this); } public long count(SearchEngine searchEngine) { return count(searchEngine, 0.0f); } public long count(SearchEngine searchEngine, float minimumScore) { return ((ElasticSearchEngine) searchEngine).count(this); } public ElasticSearchEngineQuery setBoost(float boost) { if (query instanceof BoostQuery) { ((BoostQuery<?>) query).setBoost(boost); } return this; } public ElasticSearchEngineQuery setAlias(String alias) { return setAliases(new String[] { alias }); } public ElasticSearchEngineQuery setAliases(String[] aliases) { if (aliases == null) { query = origQuery; return this; } String aliasProperty = searchEngineFactory.getAliasProperty(); BooleanQuery boolQuery2 = new BooleanQuery(); for (String alias : aliases) { boolQuery2 .add(new TermQuery(Term.string(aliasProperty, alias)), BooleanClause.Occur.SHOULD); } BooleanQuery boolQuery = new BooleanQuery(); boolQuery.add(origQuery, BooleanClause.Occur.MUST); boolQuery.add(boolQuery2, BooleanClause.Occur.MUST); this.query = boolQuery; this.aliases = aliases; return this; } public String[] getAliases() { return this.aliases; } public ElasticSearchEngineQuery rewrite() { this.rewrite = true; return this; } public boolean isRewrite() { return this.rewrite; } public boolean isSuggested() { return this.suggested; } public Query getOriginalQuery() { return this.origQuery; } public Query getQuery() { return this.query; } public XContentQueryBuilder getBuilder() { if (filter == null) { return query.getBuilder(); } else { return QueryBuilders.filteredQuery(query.getBuilder(), filter.getFilter().getBuilder()); } } public String toString() { if (query == null) { return "<null>"; } // remove the "zzz-all:" prefix return query.toString().replace(defaultSearchProperty + ":", ""); } public Object clone() throws CloneNotSupportedException { return super.clone(); } // breaks encapsulation, but we need it public void setQuery(Query query) { this.query = query; this.origQuery = query; } public void setSuggested(boolean suggested) { this.suggested = suggested; } public SearchEngineQuery setFilter(SearchEngineQueryFilter filter) { this.filter = (ElasticSearchEngineQueryFilter) filter; return this; } public ElasticSearchEngineQueryFilter getFilter() { return this.filter; } public Filter getElasticFilter() { if (filter == null) { return null; } return filter.getFilter(); } }