All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.stratio.cassandra.lucene.search.Search Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2014 Stratio (http://stratio.com)
 *
 * 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.lucene.search;

import com.google.common.base.MoreObjects;
import com.stratio.cassandra.lucene.IndexPagingState;
import com.stratio.cassandra.lucene.schema.Schema;
import com.stratio.cassandra.lucene.search.condition.Condition;
import com.stratio.cassandra.lucene.search.sort.SortField;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.Query;

import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

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 can be translated to a Lucene {@link Query} using a {@link Schema}.
 *
 * @author Andres de la Pena {@literal }
 */
public class Search {

    private static final boolean DEFAULT_FORCE_REFRESH = false;

    /** The mandatory conditions not participating in scoring. */
    public final List filter;

    /** The mandatory conditions participating in scoring. */
    public final List query;

    /** The sorting fields for the query. */
    private final List sort;

    /** If this search must refresh the index before reading it. */
    private final Boolean refresh;

    /** The paging state. */
    private final IndexPagingState paging;

    /**
     * Constructor using the specified querying, filtering, sorting and refresh options.
     *
     * @param filter the filtering {@link Condition}s not involved in scoring
     * @param query the querying {@link Condition}s participating in scoring
     * @param sort the sort fields for the query
     * @param paging the paging state
     * @param refresh if this search must refresh the index before reading it
     */
    public Search(List filter,
                  List query,
                  List sort,
                  IndexPagingState paging,
                  Boolean refresh) {
        this.filter = filter == null ? Collections.EMPTY_LIST : filter;
        this.query = query == null ? Collections.EMPTY_LIST : query;
        this.sort = sort == null ? Collections.EMPTY_LIST : sort;
        this.paging = paging;
        this.refresh = refresh == null ? DEFAULT_FORCE_REFRESH : refresh;
    }

    /**
     * Returns if this search requires post reconciliation agreement processing to preserve the order of its results.
     *
     * @return {@code true} if it requires post processing, {@code false} otherwise
     */
    public boolean requiresPostProcessing() {
        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.isEmpty();
    }

    /**
     * Returns if this search uses field sorting.
     *
     * @return {@code true} if this search uses field sorting, {@code false} otherwise
     */
    public boolean usesSorting() {
        return !sort.isEmpty();
    }

    /**
     * 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 filter.isEmpty() && query.isEmpty() && sort.isEmpty();
    }

    /**
     * Returns the Lucene {@link Query} represented by this search, with the additional optional data range filter.
     *
     * @param schema the indexing schema
     * @param range the additional data range filter, maybe {@code null}
     * @return a Lucene {@link Query}
     */
    public Query query(Schema schema, Query range) {

        BooleanQuery.Builder builder = new BooleanQuery.Builder();
        if (range != null) {
            builder.add(range, FILTER);
        }

        filter.forEach(condition -> builder.add(condition.query(schema), FILTER));
        query.forEach(condition -> builder.add(condition.query(schema), MUST));

        BooleanQuery booleanQuery = builder.build();
        return booleanQuery.clauses().isEmpty() ? new MatchAllDocsQuery() : booleanQuery;
    }

    public Query postProcessingQuery(Schema schema) {
        if (query.isEmpty()) {
            return new MatchAllDocsQuery();
        } else {
            BooleanQuery.Builder builder = new BooleanQuery.Builder();
            query.forEach(condition -> builder.add(condition.query(schema), MUST));
            return builder.build();
        }
    }

    /**
     * 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 org.apache.lucene.search.SortField}s represented by this using the specified schema.
     *
     * @param schema the indexing schema to be used
     * @return the Lucene sort fields represented by this using {@code schema}
     */
    public List sortFields(Schema schema) {
        return sort.stream().map(s -> s.sortField(schema)).collect(Collectors.toList());
    }

    public IndexPagingState paging() {
        return paging;
    }

    /**
     * Returns the names of the involved fields when post processing.
     *
     * @return the names of the involved fields
     */
    public Set postProcessingFields() {
        Set fields = new LinkedHashSet<>();
        query.forEach(condition -> fields.addAll(condition.postProcessingFields()));
        sort.forEach(condition -> fields.addAll(condition.postProcessingFields()));
        return fields;
    }

    /**
     * Validates this {@link Search} against the specified {@link Schema}.
     *
     * @param schema a {@link Schema}
     * @return this
     */
    public Search validate(Schema schema) {
        filter.forEach(condition -> condition.query(schema));
        query.forEach(condition -> condition.query(schema));
        sort.forEach(field -> field.sortField(schema));
        return this;
    }

    /** {@inheritDoc} */
    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this)
                          .add("filter", filter)
                          .add("query", query)
                          .add("sort", sort)
                          .add("refresh", refresh)
                          .add("paging", paging)
                          .toString();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy