/* * Licensed to STRATIO (C) under one or more contributor license agreements. * See the NOTICE file distributed with this work for additional information * regarding copyright ownership. The STRATIO (C) licenses this file * to you 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.lucene.search; import com.google.common.base.MoreObjects; import com.stratio.cassandra.lucene.schema.Schema; import com.stratio.cassandra.lucene.search.condition.Condition; import com.stratio.cassandra.lucene.search.sort.Sort; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.SortField; import java.util.List; import static org.apache.lucene.search.BooleanClause.Occur.FILTER; import static org.apache.lucene.search.BooleanClause.Occur.MUST; /** * 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 {@literal <adelapena@stratio.com>} */ public class Search { private static final boolean DEFAULT_FORCE_REFRESH = false; /** The {@link Condition} for querying, maybe {@code null} meaning no querying. */ private final Condition query; /** The {@link Condition} for filtering, maybe {@code null} meaning no filtering. */ private final Condition filter; /** * 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. */ private final Sort sort; /** If this search must refresh the index before reading it. */ private final Boolean refresh; /** * Constructor using the specified querying, filtering, sorting and refresh options. * * @param query the condition for querying, maybe {@code null} meaning no querying * @param filter the condition for filtering, maybe {@code null} meaning no filtering * @param sort the 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 * @param refresh if this search must refresh the index before reading it */ public Search(Condition query, Condition filter, Sort sort, Boolean refresh) { this.query = query; this.filter = filter; this.sort = sort; this.refresh = refresh == null ? DEFAULT_FORCE_REFRESH : refresh; } public boolean isTopK() { return usesRelevance() || usesSorting(); } /** * Returns if this search requires full ranges scan. * * @return {@code true} if this search requires full ranges scan, {code null} otherwise */ public boolean requiresFullScan() { return usesRelevance() || usesSorting() || refresh && isEmpty(); } /** * Returns if this search uses Lucene relevance formula. * * @return {@code true} if this search uses Lucene relevance formula, {@code false} otherwise */ public boolean usesRelevance() { return query != null; } /** * Returns if this search uses field sorting. * * @return {@code true} if this search uses field sorting, {@code false} otherwise */ public boolean usesSorting() { return sort != null; } /** * Returns if this search doesn't specify any filter, query or sort. * * @return {@code true} if this search doesn't specify any filter, query or sort, {@code false} otherwise */ public boolean isEmpty() { return query == null && filter == null && sort == null; } /** * Returns the field sorting to be used, maybe {@code null} meaning no field sorting. * * @return the Lucene's sort */ public Sort getSort() { return this.sort; } /** * Returns if this search needs to refresh the index before reading it. * * @return {@code true} if this search needs to refresh the index before reading it, {@code false} otherwise. */ public boolean refresh() { return refresh; } /** * Returns the Lucene {@link SortField}s represented by this using the specified {@link Schema}. Maybe {@code null} * meaning no sorting. * * @param schema the {@link Schema} * @return the Lucene {@link SortField}s represented by this using {@code schema} */ public List<SortField> sortFields(Schema schema) { return sort == null ? null : sort.sortFields(schema); } /** * Returns the Lucene {@link Query} represented by this using the specified {@link Schema}. * * @param schema the {@link Schema} * @return a Lucene {@link Query} */ public Query query(Schema schema) { if (query == null && filter == null) { return new MatchAllDocsQuery(); } else if (filter == null) { return query.query(schema); } else if (query == null) { return filter.filter(schema); } else { BooleanQuery.Builder builder = new BooleanQuery.Builder(); builder.add(filter.filter(schema), FILTER); builder.add(query.query(schema), MUST); return builder.build(); } } /** * Validates this {@link Search} against the specified {@link Schema}. * * @param schema a {@link Schema} */ public void validate(Schema schema) { if (query != null) { query.filter(schema); } if (filter != null) { filter.filter(schema); } if (sort != null) { sort.sortFields(schema); } } /** {@inheritDoc} */ @Override public String toString() { return MoreObjects.toStringHelper(this) .add("query", query) .add("filter", filter) .add("sort", sort) .add("refresh", refresh) .toString(); } }