com.couchbase.client.java.search.SearchQuery Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of java-client Show documentation
Show all versions of java-client Show documentation
The official Couchbase Java SDK
/*
* Copyright (c) 2016 Couchbase, Inc.
*
* 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.couchbase.client.java.search;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import com.couchbase.client.core.annotations.InterfaceAudience;
import com.couchbase.client.core.annotations.InterfaceStability;
import com.couchbase.client.java.Bucket;
import com.couchbase.client.java.MutationState;
import com.couchbase.client.java.document.Document;
import com.couchbase.client.java.document.json.JsonArray;
import com.couchbase.client.java.document.json.JsonObject;
import com.couchbase.client.java.env.CouchbaseEnvironment;
import com.couchbase.client.java.search.facet.SearchFacet;
import com.couchbase.client.java.search.queries.AbstractFtsQuery;
import com.couchbase.client.java.search.queries.BooleanFieldQuery;
import com.couchbase.client.java.search.queries.BooleanQuery;
import com.couchbase.client.java.search.queries.ConjunctionQuery;
import com.couchbase.client.java.search.queries.DateRangeQuery;
import com.couchbase.client.java.search.queries.DisjunctionQuery;
import com.couchbase.client.java.search.queries.DocIdQuery;
import com.couchbase.client.java.search.queries.MatchAllQuery;
import com.couchbase.client.java.search.queries.MatchNoneQuery;
import com.couchbase.client.java.search.queries.MatchPhraseQuery;
import com.couchbase.client.java.search.queries.MatchQuery;
import com.couchbase.client.java.search.queries.NumericRangeQuery;
import com.couchbase.client.java.search.queries.PhraseQuery;
import com.couchbase.client.java.search.queries.PrefixQuery;
import com.couchbase.client.java.search.queries.RegexpQuery;
import com.couchbase.client.java.search.queries.StringQuery;
import com.couchbase.client.java.search.queries.TermQuery;
import com.couchbase.client.java.search.queries.WildcardQuery;
import com.couchbase.client.java.search.result.SearchQueryResult;
import com.couchbase.client.java.search.result.SearchQueryRow;
import com.couchbase.client.java.subdoc.DocumentFragment;
/**
* The FTS API entry point. Describes an FTS query entirely (index, query body and parameters) and can
* be used at the {@link Bucket} level to perform said query. Also has factory methods for all types of
* fts queries (as in the various types a query body can have: term, match, conjunction, ...).
*
* @author Simon Baslé
* @author Michael Nitschinger
* @since 2.3.0
*/
@InterfaceStability.Experimental
@InterfaceAudience.Public
public class SearchQuery {
private final String indexName;
private final AbstractFtsQuery queryPart;
//top level search parameters
private Integer limit;
private Integer skip;
private Boolean explain;
private HighlightStyle highlightStyle;
private String[] highlightFields;
private String[] fields;
private Map facets;
private Long serverSideTimeout;
private ScanConsistency consistency;
private MutationState mutationState;
/**
* Prepare an FTS {@link SearchQuery} on an index. Top level query parameters can be set after that
* by using the fluent API.
*
* @param indexName the FTS index to search in.
* @param queryPart the body of the FTS query (eg. a match phrase query).
*/
public SearchQuery(String indexName, AbstractFtsQuery queryPart) {
this.indexName = indexName;
this.queryPart = queryPart;
this.highlightFields = new String[0];
this.fields = new String[0];
this.facets = new HashMap();
this.consistency = null;
this.mutationState = null;
}
/**
* @return the name of the index targeted by this query.
*/
public String indexName() {
return indexName;
}
/**
* @return the actual query body.
*/
public AbstractFtsQuery query() {
return queryPart;
}
/**
* Exports the whole query as a {@link JsonObject}.
*
* @see #injectParams(JsonObject) for the part that deals with global parameters
* @see AbstractFtsQuery#injectParamsAndBoost(JsonObject) for the part that deals with the "query" entry
*/
public JsonObject export() {
JsonObject result = JsonObject.create();
injectParams(result);
JsonObject queryJson = JsonObject.create();
queryPart.injectParamsAndBoost(queryJson);
return result.put("query", queryJson);
}
/**
* Inject the top level parameters of a query into a prepared {@link JsonObject}
* that represents the root of the query.
*
* @param queryJson the prepared {@link JsonObject} for the whole query.
*/
public void injectParams(JsonObject queryJson) {
if (limit != null && limit >= 0) {
queryJson.put("size", limit);
}
if (skip != null && skip >= 0) {
queryJson.put("from", skip);
}
if (explain != null) {
queryJson.put("explain", explain);
}
if (highlightStyle != null) {
JsonObject highlight = JsonObject.create();
highlight.put("style", highlightStyle.name().toLowerCase());
if (highlightFields != null && highlightFields.length > 0) {
highlight.put("fields", JsonArray.from(highlightFields));
}
queryJson.put("highlight", highlight);
}
if (fields != null && fields.length > 0) {
queryJson.put("fields", JsonArray.from(fields));
}
if (!this.facets.isEmpty()) {
JsonObject facets = JsonObject.create();
for (Map.Entry entry : this.facets.entrySet()) {
JsonObject facetJson = JsonObject.create();
entry.getValue().injectParams(facetJson);
facets.put(entry.getKey(), facetJson);
}
queryJson.put("facets", facets);
}
JsonObject control = JsonObject.empty();
//check need for timeout
if(serverSideTimeout != null) {
control.put("timeout", serverSideTimeout);
}
//check need for consistency
if (consistency != null || mutationState != null) {
JsonObject consistencyJson = JsonObject.create();
if (consistency == ScanConsistency.NOT_BOUNDED) {
consistencyJson.put("level", "");
} else if (mutationState != null) {
consistencyJson.put("level", "at_plus");
consistencyJson.put("vectors", JsonObject.create().put(this.indexName, mutationState.exportForFts()));
}
control.put("consistency", consistencyJson);
}
//if any control was set, inject it
if (!control.isEmpty()) {
queryJson.put("ctl", control);
}
}
/* =====================================
* Search parameter builders and getters
* ===================================== */
/**
* Add a limit to the query on the number of hits it can return.
*
* @param limit the maximum number of hits to return.
* @return this SearchQuery for chaining.
*/
public SearchQuery limit(int limit) {
this.limit = limit;
return this;
}
/**
* Set the number of hits to skip (eg. for pagination).
*
* @param skip the number of results to skip.
* @return this SearchQuery for chaining.
*/
public SearchQuery skip(int skip) {
this.skip = skip;
return this;
}
/**
* Activates the explanation of each result hit in the response.
*
* @return this SearchQuery for chaining.
*/
public SearchQuery explain() {
return explain(true);
}
/**
* Activates or deactivates the explanation of each result hit in the response, according to the parameter.
*
* @param explain should the response include an explanation of each hit (true) or not (false)?
* @return this SearchQuery for chaining.
*/
public SearchQuery explain(boolean explain) {
this.explain = explain;
return this;
}
/**
* Configures the highlighting of matches in the response.
*
* This drives the inclusion of the {@link SearchQueryRow#fragments() fragments} in each {@link SearchQueryRow hit}.
*
* Note that to be highlighted, the fields must be stored in the FTS index.
*
* @param style the {@link HighlightStyle} to apply.
* @param fields the optional fields on which to highlight. If none, all fields where there is a match are highlighted.
* @return this SearchQuery for chaining.
*/
public SearchQuery highlight(HighlightStyle style, String... fields) {
this.highlightStyle = style;
if (fields != null && fields.length > 0) {
highlightFields = fields;
}
return this;
}
/**
* Clears any previously configured highlighting.
*
* @return this SearchQuery for chaining.
* @see #highlight(HighlightStyle, String...)
*/
public SearchQuery clearHighlight() {
this.highlightStyle = null;
this.highlightFields = null;
return this;
}
/**
* Configures the list of fields for which the whole value should be included in the response. If empty, no field
* values are included.
*
* This drives the inclusion of the {@link SearchQueryRow#fields() fields} in each {@link SearchQueryRow hit}.
*
* Note that to be highlighted, the fields must be stored in the FTS index.
*
* @param fields
* @return this SearchQuery for chaining.
*/
public SearchQuery fields(String... fields) {
if (fields != null) {
this.fields = fields;
}
return this;
}
/**
* Adds one {@link SearchFacet} to the query.
*
* This is an additive operation (the given facets are added to any facet previously requested),
* but if an existing facet has the same name it will be replaced.
*
* This drives the inclusion of the {@link SearchQueryResult#facets()} facets} in the {@link SearchQueryResult}.
*
* Note that to be faceted, a field's value must be stored in the FTS index.
*
* @param facetName the name of the facet to add (or replace if one already exists with same name).
* @param facet the facet to add.
*/
public SearchQuery addFacet(String facetName, SearchFacet facet) {
if (facet == null || facetName == null) {
throw new NullPointerException("Facet name and description must not be null");
}
this.facets.put(facetName, facet);
return this;
}
/**
* Clears all previously added {@link SearchFacet}.
*
* @return this SearchQuery for chaining.
* @see #addFacet(String, SearchFacet)
*/
public SearchQuery clearFacets() {
this.facets.clear();
return this;
}
/**
* Sets the server side timeout. By default, the SDK will set this value to the configured
* {@link CouchbaseEnvironment#searchTimeout() searchTimeout} from the environment.
*
* @param timeout the server side timeout to apply.
* @param unit the unit for the timeout.
* @return this SearchQuery for chaining.
*/
public SearchQuery serverSideTimeout(long timeout, TimeUnit unit) {
this.serverSideTimeout = unit.toMillis(timeout);
return this;
}
/**
* Sets the unparameterized consistency to consider for this FTS query. This replaces any
* consistency tuning previously set.
*
* @param consistency the simple consistency to use.
* @return this SearchQuery for chaining.
*/
public SearchQuery scanConsistency(ScanConsistency consistency) {
this.consistency = consistency;
this.mutationState = null;
return this;
}
/**
* Sets the consistency to consider for this FTS query to AT_PLUS and
* uses the mutation information from the given documents to parameterize
* the consistency. This replaces any consistency tuning previously set.
*
* @param docs one or mode {@link Document} to get mutation state information from.
* @return this SearchQuery for chaining.
*/
public SearchQuery consistentWith(Document... docs) {
this.consistency = null;
this.mutationState = MutationState.from(docs);
return this;
}
/**
* Sets the consistency to consider for this FTS query to AT_PLUS and
* uses the mutation information from the given document fragments to parameterize
* the consistency. This replaces any consistency tuning previously set.
*
* @param fragments one or mode {@link DocumentFragment} to get mutation state information from.
* @return this SearchQuery for chaining.
*/
public SearchQuery consistentWith(DocumentFragment... fragments) {
this.consistency = null;
this.mutationState = MutationState.from(fragments);
return this;
}
/**
* Sets the consistency to consider for this FTS query to AT_PLUS and
* uses the {@link MutationState} directly to parameterize the consistency.
* This replaces any consistency tuning previously set.
*
* @param mutationState the {@link MutationState} information to work with.
* @return this SearchQuery for chaining.
*/
public SearchQuery consistentWith(MutationState mutationState) {
this.consistency = null;
this.mutationState = mutationState;
return this;
}
/**
* @return the value of the {@link #limit(int)} parameter, or null if it was not set.
*/
public Integer getLimit() {
return limit;
}
/**
* @return the value of the {@link #skip(int)} parameter, or null if it was not set.
*/
public Integer getSkip() {
return skip;
}
/**
* @return the value of the {@link #highlight(HighlightStyle, String...) highlight style} parameter,
* or null if it was not set.
*/
public HighlightStyle getHighlightStyle() {
return highlightStyle;
}
/**
* @return the value of the {@link #highlight(HighlightStyle, String...) highlight fields} parameter,
* or an empty array if it was not set.
*/
public String[] getHighlightFields() {
return highlightFields;
}
/**
* @return the value of the {@link #fields(String...)} parameter, or an empty array if it was not set.
*/
public String[] getFields() {
return fields;
}
/**
* @return the Map of {@link #addFacet(String, SearchFacet) facets (by name)}, or an empty Map if it was not set.
*/
public Map getFacets() {
return facets;
}
/**
* @return the value of the {@link #serverSideTimeout(long, TimeUnit)} parameter, or null if it was not set.
*/
public Long getServerSideTimeout() {
return serverSideTimeout;
}
/* ===============================
* Factory methods for FTS queries
* =============================== */
/** Prepare a {@link StringQuery} body. */
public static StringQuery string(String query) {
return new StringQuery(query);
}
/** Prepare a {@link MatchQuery} body. */
public static MatchQuery match(String match) {
return new MatchQuery(match);
}
/** Prepare a {@link MatchPhraseQuery} body. */
public static MatchPhraseQuery matchPhrase(String matchPhrase) {
return new MatchPhraseQuery(matchPhrase);
}
/** Prepare a {@link PrefixQuery} body. */
public static PrefixQuery prefix(String prefix) {
return new PrefixQuery(prefix);
}
/** Prepare a {@link RegexpQuery} body. */
public static RegexpQuery regexp(String regexp) {
return new RegexpQuery(regexp);
}
/** Prepare a {@link NumericRangeQuery} body. */
public static NumericRangeQuery numericRange() {
return new NumericRangeQuery();
}
/** Prepare a {@link DateRangeQuery} body. */
public static DateRangeQuery dateRange() {
return new DateRangeQuery();
}
/** Prepare a {@link DisjunctionQuery} body. */
public static DisjunctionQuery disjuncts(AbstractFtsQuery... queries) {
return new DisjunctionQuery(queries);
}
/** Prepare a {@link ConjunctionQuery} body. */
public static ConjunctionQuery conjuncts(AbstractFtsQuery... queries) {
return new ConjunctionQuery(queries);
}
/** Prepare a {@link BooleanQuery} body. */
public static BooleanQuery booleans() {
return new BooleanQuery();
}
/** Prepare a {@link WildcardQuery} body. */
public static WildcardQuery wildcard(String wildcard) {
return new WildcardQuery(wildcard);
}
/** Prepare a {@link DocIdQuery} body. */
public static DocIdQuery docId(String... docIds) {
return new DocIdQuery(docIds);
}
/** Prepare a {@link BooleanFieldQuery} body. */
public static BooleanFieldQuery booleanField(boolean value) {
return new BooleanFieldQuery(value);
}
/** Prepare a {@link TermQuery} body. */
public static TermQuery term(String term) {
return new TermQuery(term);
}
/** Prepare a {@link PhraseQuery} body. */
public static PhraseQuery phrase(String... terms) {
return new PhraseQuery(terms);
}
/** Prepare a {@link MatchAllQuery} body. */
public static MatchAllQuery matchAll() {
return new MatchAllQuery();
}
/** Prepare a {@link MatchNoneQuery} body. */
public static MatchNoneQuery matchNone() {
return new MatchNoneQuery();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy