/* * Copyright 2014, Stratio. * * 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 com.stratio.cassandra.index.query; import com.google.common.base.Objects; import com.stratio.cassandra.index.schema.Schema; import com.stratio.cassandra.util.JsonSerializer; import com.stratio.cassandra.util.Log; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.lucene.search.*; import org.codehaus.jackson.annotate.JsonCreator; import org.codehaus.jackson.annotate.JsonProperty; /** * Class representing an Lucene index search. It is formed by an optional querying {@link Condition} and an optional * filtering {@link Condition}. It can be translated to a Lucene {@link Query} using a {@link Schema}. * * @author Andres de la Pena <adelapena@stratio.com> */ public class Search { /** he {@link Condition} for querying, maybe {@code null} meaning no querying. */ @JsonProperty("query") private Condition queryCondition; /** The {@link Condition} for filtering, maybe {@code null} meaning no filtering. */ @JsonProperty("filter") private Condition filterCondition; /** * The {@link Sort} for the query. Note that is the order in which the data will be read before querying, not the * order of the results after querying. */ @JsonProperty("sort") private Sort sort; /** * Returns a new {@link Search} composed by the specified querying and filtering conditions. * * @param queryCondition The {@link Condition} for querying, maybe {@code null} meaning no querying. * @param filterCondition The {@link Condition} for filtering, maybe {@code null} meaning no filtering. * @param sort The {@link Sort} for the query. Note that is the order in which the data will be read * before querying, not the order of the results after querying. */ @JsonCreator public Search(@JsonProperty("query") Condition queryCondition, @JsonProperty("filter") Condition filterCondition, @JsonProperty("sort") Sort sort) { this.queryCondition = queryCondition; this.filterCondition = filterCondition; this.sort = sort; } /** * Returns a new {@link Search} from the specified JSON {@code String}. * * @param json A JSON {@code String} representing a {@link Search}. * @return The {@link Search} represented by the specified JSON {@code String}. */ public static Search fromJson(String json) { try { return JsonSerializer.fromString(json, Search.class); } catch (Exception e) { String message = String.format("Unparseable JSON search: %s", e.getMessage()); Log.error(e, message); throw new IllegalArgumentException(message, e); } } /** * Returns the JSON representation of this object. * * @return the JSON representation of this object. */ public String toJson() { try { return JsonSerializer.toString(this); } catch (Exception e) { String message = String.format("Unformateable JSON search: %s", e.getMessage()); Log.error(e, message); throw new IllegalArgumentException(message, e); } } /** * Returns {@code true} if the results must be ordered by relevance. If {@code false}, then the results are sorted * by the natural Cassandra's order. Results must be ordered by relevance if the querying condition is not {code * null}. * <p/> * Relevance is used when the query condition is set, and it is not used when only the clusteringKeyFilter condition * is set. * * @return {@code true} if the results must be ordered by relevance. If {@code false}, then the results must be * sorted by the natural Cassandra's order. */ public boolean usesRelevanceOrSorting() { return queryCondition != null || sort != null; } /** * Returns {@code true} if this search uses Lucene relevance formula, {@code false} otherwise. * * @return {@code true} if this search uses Lucene relevance formula, {@code false} otherwise. */ public boolean usesRelevance() { return queryCondition != null; } /** * Returns {@code true} if this search uses field sorting, {@code false} otherwise. * * @return {@code true} if this search uses field sorting, {@code false} otherwise. */ public boolean usesSorting() { return sort != null; } /** * Returns the field sorting to be used, maybe {@code null} meaning no field sorting. * * @return The field sorting to be used, maybe {@code null} meaning no field sorting. */ public Sort getSort() { return this.sort; } /** * Returns the Lucene {@link org.apache.lucene.search.Sort} represented by this {@link Sort} using the specified * {@link Schema}. Maybe {@code null} meaning no sorting. * * @param schema A {@link Schema}. * @return The Lucene {@link org.apache.lucene.search.Sort} represented by this {@link Sort} using {@code schema}. */ public org.apache.lucene.search.Sort sort(Schema schema) { return sort == null ? null : sort.sort(schema); } /** * Returns the Lucene {@link Query} representation of this search. This {@link Query} include both the querying and * filtering {@link Condition}s. If none of them is set, then a {@link MatchAllDocsQuery} is returned, so it never * returns {@code null}. * * @param schema The {@link Schema} to be used. * @param rangeQuery An additional range {@link Query} to be used. * @return The Lucene {@link Query} representation of this search. */ public Query query(Schema schema, Query rangeQuery) { if (queryCondition == null && filterCondition == null && rangeQuery == null) { return new MatchAllDocsQuery(); } BooleanQuery booleanQuery = new BooleanQuery(); if (queryCondition != null) { Query query = queryCondition.query(schema); booleanQuery.add(query, BooleanClause.Occur.MUST); } if (filterCondition != null) { Query query = new ConstantScoreQuery(filterCondition.query(schema)); booleanQuery.add(query, BooleanClause.Occur.MUST); } if (rangeQuery != null) { booleanQuery.add(rangeQuery, BooleanClause.Occur.MUST); } return booleanQuery; } /** * Validates this {@link Search} against the specified {@link Schema}. * * @param schema A {@link Schema}. */ public void validate(Schema schema) { if (queryCondition != null || filterCondition != null) { query(schema, null); } if (sort != null) { sort.sort(schema); } } /** {@inheritDoc} */ @Override public String toString() { return Objects.toStringHelper(this) .add("queryCondition", queryCondition) .add("filterCondition", filterCondition) .add("sort", sort) .toString(); } }