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

org.codelibs.elasticsearch.search.suggest.SuggestBuilder Maven / Gradle / Ivy

/*
 * Licensed to Elasticsearch under one or more contributor
 * license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright
 * ownership. Elasticsearch 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 org.codelibs.elasticsearch.search.suggest;

import org.codelibs.elasticsearch.action.support.ToXContentToBytes;
import org.codelibs.elasticsearch.common.Nullable;
import org.codelibs.elasticsearch.common.ParseField;
import org.codelibs.elasticsearch.common.ParseFieldMatcher;
import org.codelibs.elasticsearch.common.ParsingException;
import org.codelibs.elasticsearch.common.io.stream.StreamInput;
import org.codelibs.elasticsearch.common.io.stream.StreamOutput;
import org.codelibs.elasticsearch.common.io.stream.Writeable;
import org.codelibs.elasticsearch.common.lucene.BytesRefs;
import org.codelibs.elasticsearch.common.xcontent.XContentBuilder;
import org.codelibs.elasticsearch.common.xcontent.XContentParser;
import org.codelibs.elasticsearch.index.query.QueryParseContext;
import org.codelibs.elasticsearch.index.query.QueryShardContext;
import org.codelibs.elasticsearch.search.suggest.SuggestionSearchContext.SuggestionContext;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;

/**
 * Defines how to perform suggesting. This builders allows a number of global options to be specified and
 * an arbitrary number of {SuggestionBuilder} instances.
 * 

* Suggesting works by suggesting terms/phrases that appear in the suggest text that are similar compared * to the terms in provided text. These suggestions are based on several options described in this class. */ public class SuggestBuilder extends ToXContentToBytes implements Writeable { protected static final ParseField GLOBAL_TEXT_FIELD = new ParseField("text"); private String globalText; private final Map> suggestions = new HashMap<>(); /** * Build an empty SuggestBuilder. */ public SuggestBuilder() { } /** * Read from a stream. */ public SuggestBuilder(StreamInput in) throws IOException { globalText = in.readOptionalString(); final int size = in.readVInt(); for (int i = 0; i < size; i++) { suggestions.put(in.readString(), in.readNamedWriteable(SuggestionBuilder.class)); } } @Override public void writeTo(StreamOutput out) throws IOException { out.writeOptionalString(globalText); final int size = suggestions.size(); out.writeVInt(size); for (Entry> suggestion : suggestions.entrySet()) { out.writeString(suggestion.getKey()); out.writeNamedWriteable(suggestion.getValue()); } } /** * Sets the text to provide suggestions for. The suggest text is a required option that needs * to be set either via this setter or via the {org.codelibs.elasticsearch.search.suggest.SuggestionBuilder#text(String)} method. *

* The suggest text gets analyzed by the suggest analyzer or the suggest field search analyzer. * For each analyzed token, suggested terms are suggested if possible. */ public SuggestBuilder setGlobalText(@Nullable String globalText) { this.globalText = globalText; return this; } /** * Gets the global suggest text */ @Nullable public String getGlobalText() { return globalText; } /** * Adds an {org.codelibs.elasticsearch.search.suggest.SuggestionBuilder} instance under a user defined name. * The order in which the Suggestions are added, is the same as in the response. * @throws IllegalArgumentException if two suggestions added have the same name */ public SuggestBuilder addSuggestion(String name, SuggestionBuilder suggestion) { Objects.requireNonNull(name, "every suggestion needs a name"); if (suggestions.get(name) == null) { suggestions.put(name, suggestion); } else { throw new IllegalArgumentException("already added another suggestion with name [" + name + "]"); } return this; } /** * Get all the Suggestions that were added to the global {SuggestBuilder}, * together with their names */ public Map> getSuggestions() { return suggestions; } @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(); if (globalText != null) { builder.field("text", globalText); } for (Entry> suggestion : suggestions.entrySet()) { builder.startObject(suggestion.getKey()); suggestion.getValue().toXContent(builder, params); builder.endObject(); } builder.endObject(); return builder; } public static SuggestBuilder fromXContent(QueryParseContext parseContext, Suggesters suggesters) throws IOException { XContentParser parser = parseContext.parser(); parseContext.getParseFieldMatcher(); SuggestBuilder suggestBuilder = new SuggestBuilder(); String fieldName = null; if (parser.currentToken() == null) { // when we parse from RestSuggestAction the current token is null, advance the token parser.nextToken(); } assert parser.currentToken() == XContentParser.Token.START_OBJECT : "current token must be a start object"; XContentParser.Token token; while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { fieldName = parser.currentName(); } else if (token.isValue()) { if (GLOBAL_TEXT_FIELD.match(fieldName)) { suggestBuilder.setGlobalText(parser.text()); } else { throw new IllegalArgumentException("[suggest] does not support [" + fieldName + "]"); } } else if (token == XContentParser.Token.START_OBJECT) { String suggestionName = fieldName; if (suggestionName == null) { throw new IllegalArgumentException("suggestion must have name"); } suggestBuilder.addSuggestion(suggestionName, SuggestionBuilder.fromXContent(parseContext, suggesters)); } else { throw new ParsingException(parser.getTokenLocation(), "unexpected token [" + token + "] after [" + fieldName + "]"); } } return suggestBuilder; } public SuggestionSearchContext build(QueryShardContext context) throws IOException { SuggestionSearchContext suggestionSearchContext = new SuggestionSearchContext(); for (Entry> suggestion : suggestions.entrySet()) { SuggestionContext suggestionContext = suggestion.getValue().build(context); if (suggestionContext.getText() == null) { if (globalText == null) { throw new IllegalArgumentException("The required text option is missing"); } suggestionContext.setText(BytesRefs.toBytesRef(globalText)); } suggestionSearchContext.addSuggestion(suggestion.getKey(), suggestionContext); } return suggestionSearchContext; } @Override public boolean equals(Object other) { if (this == other) { return true; } if (other == null || getClass() != other.getClass()) { return false; } @SuppressWarnings("unchecked") SuggestBuilder o = (SuggestBuilder)other; return Objects.equals(globalText, o.globalText) && Objects.equals(suggestions, o.suggestions); } @Override public int hashCode() { return Objects.hash(globalText, suggestions); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy