Initial refactoring for phrase suggester
Adding initial serialization methods (readFrom, writeTo) to the PhraseSuggestionBuilder, also adding the base test framework for serialiazation testing, equals and hashCode. Moving SuggestionBuilder out of the global SuggestBuilder for better readability.
This commit is contained in:
parent
60180fecf8
commit
c00c0fa020
|
@ -30,6 +30,7 @@ import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.xcontent.XContentHelper;
|
import org.elasticsearch.common.xcontent.XContentHelper;
|
||||||
import org.elasticsearch.search.suggest.SuggestBuilder;
|
import org.elasticsearch.search.suggest.SuggestBuilder;
|
||||||
|
import org.elasticsearch.search.suggest.SuggestionBuilder;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -99,10 +100,10 @@ public final class SuggestRequest extends BroadcastRequest<SuggestRequest> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set a new source using a {@link org.elasticsearch.search.suggest.SuggestBuilder.SuggestionBuilder}
|
* set a new source using a {@link org.elasticsearch.search.suggest.SuggestionBuilder}
|
||||||
* for completion suggestion lookup
|
* for completion suggestion lookup
|
||||||
*/
|
*/
|
||||||
public SuggestRequest suggest(SuggestBuilder.SuggestionBuilder suggestionBuilder) {
|
public SuggestRequest suggest(SuggestionBuilder suggestionBuilder) {
|
||||||
return suggest(suggestionBuilder.buildAsBytes(Requests.CONTENT_TYPE));
|
return suggest(suggestionBuilder.buildAsBytes(Requests.CONTENT_TYPE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||||
import org.elasticsearch.search.suggest.SuggestBuilder;
|
import org.elasticsearch.search.suggest.SuggestBuilder;
|
||||||
import org.elasticsearch.search.suggest.SuggestBuilder.SuggestionBuilder;
|
import org.elasticsearch.search.suggest.SuggestionBuilder;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ public class SuggestRequestBuilder extends BroadcastOperationRequestBuilder<Sugg
|
||||||
/**
|
/**
|
||||||
* Add a definition for suggestions to the request
|
* Add a definition for suggestions to the request
|
||||||
*/
|
*/
|
||||||
public <T> SuggestRequestBuilder addSuggestion(SuggestionBuilder<T> suggestion) {
|
public SuggestRequestBuilder addSuggestion(SuggestionBuilder<?> suggestion) {
|
||||||
suggest.addSuggestion(suggestion);
|
suggest.addSuggestion(suggestion);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ import org.elasticsearch.common.text.Text;
|
||||||
import org.elasticsearch.index.query.QueryBuilder;
|
import org.elasticsearch.index.query.QueryBuilder;
|
||||||
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder;
|
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder;
|
||||||
import org.elasticsearch.search.rescore.RescoreBuilder;
|
import org.elasticsearch.search.rescore.RescoreBuilder;
|
||||||
|
import org.elasticsearch.search.suggest.SuggestionBuilder;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.joda.time.DateTimeZone;
|
import org.joda.time.DateTimeZone;
|
||||||
|
|
||||||
|
@ -281,6 +282,14 @@ public abstract class StreamInput extends InputStream {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Float readOptionalFloat() throws IOException {
|
||||||
|
if (readBoolean()) {
|
||||||
|
return readFloat();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public Integer readOptionalVInt() throws IOException {
|
public Integer readOptionalVInt() throws IOException {
|
||||||
if (readBoolean()) {
|
if (readBoolean()) {
|
||||||
|
@ -683,6 +692,13 @@ public abstract class StreamInput extends InputStream {
|
||||||
return readNamedWriteable(RescoreBuilder.class);
|
return readNamedWriteable(RescoreBuilder.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a {@link SuggestionBuilder} from the current stream
|
||||||
|
*/
|
||||||
|
public SuggestionBuilder<?> readSuggestion() throws IOException {
|
||||||
|
return readNamedWriteable(SuggestionBuilder.class);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a {@link org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder} from the current stream
|
* Reads a {@link org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder} from the current stream
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -37,6 +37,7 @@ import org.elasticsearch.common.text.Text;
|
||||||
import org.elasticsearch.index.query.QueryBuilder;
|
import org.elasticsearch.index.query.QueryBuilder;
|
||||||
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder;
|
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder;
|
||||||
import org.elasticsearch.search.rescore.RescoreBuilder;
|
import org.elasticsearch.search.rescore.RescoreBuilder;
|
||||||
|
import org.elasticsearch.search.suggest.SuggestionBuilder;
|
||||||
import org.joda.time.ReadableInstant;
|
import org.joda.time.ReadableInstant;
|
||||||
|
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
|
@ -230,6 +231,15 @@ public abstract class StreamOutput extends OutputStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void writeOptionalFloat(@Nullable Float floatValue) throws IOException {
|
||||||
|
if (floatValue == null) {
|
||||||
|
writeBoolean(false);
|
||||||
|
} else {
|
||||||
|
writeBoolean(true);
|
||||||
|
writeFloat(floatValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void writeOptionalText(@Nullable Text text) throws IOException {
|
public void writeOptionalText(@Nullable Text text) throws IOException {
|
||||||
if (text == null) {
|
if (text == null) {
|
||||||
writeInt(-1);
|
writeInt(-1);
|
||||||
|
@ -684,4 +694,11 @@ public abstract class StreamOutput extends OutputStream {
|
||||||
public void writeRescorer(RescoreBuilder<?> rescorer) throws IOException {
|
public void writeRescorer(RescoreBuilder<?> rescorer) throws IOException {
|
||||||
writeNamedWriteable(rescorer);
|
writeNamedWriteable(rescorer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes a {@link SuggestionBuilder} to the current stream
|
||||||
|
*/
|
||||||
|
public void writeSuggestion(SuggestionBuilder suggestion) throws IOException {
|
||||||
|
writeNamedWriteable(suggestion);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,14 +42,14 @@ public class SuggestBuilder extends ToXContentToBytes {
|
||||||
public SuggestBuilder() {
|
public SuggestBuilder() {
|
||||||
this.name = null;
|
this.name = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SuggestBuilder(String name) {
|
public SuggestBuilder(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the text to provide suggestions for. The suggest text is a required option that needs
|
* 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 {@link org.elasticsearch.search.suggest.SuggestBuilder.SuggestionBuilder#setText(String)} method.
|
* to be set either via this setter or via the {@link org.elasticsearch.search.suggest.SuggestionBuilder#text(String)} method.
|
||||||
* <p>
|
* <p>
|
||||||
* The suggest text gets analyzed by the suggest analyzer or the suggest field search analyzer.
|
* 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.
|
* For each analyzed token, suggested terms are suggested if possible.
|
||||||
|
@ -67,7 +67,7 @@ public class SuggestBuilder extends ToXContentToBytes {
|
||||||
suggestions.add(suggestion);
|
suggestions.add(suggestion);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all suggestions with the defined names.
|
* Returns all suggestions with the defined names.
|
||||||
*/
|
*/
|
||||||
|
@ -82,7 +82,7 @@ public class SuggestBuilder extends ToXContentToBytes {
|
||||||
} else {
|
} else {
|
||||||
builder.startObject(name);
|
builder.startObject(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (globalText != null) {
|
if (globalText != null) {
|
||||||
builder.field("text", globalText);
|
builder.field("text", globalText);
|
||||||
}
|
}
|
||||||
|
@ -92,125 +92,4 @@ public class SuggestBuilder extends ToXContentToBytes {
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static abstract class SuggestionBuilder<T> extends ToXContentToBytes {
|
|
||||||
|
|
||||||
private String name;
|
|
||||||
private String suggester;
|
|
||||||
private String text;
|
|
||||||
private String prefix;
|
|
||||||
private String regex;
|
|
||||||
private String field;
|
|
||||||
private String analyzer;
|
|
||||||
private Integer size;
|
|
||||||
private Integer shardSize;
|
|
||||||
|
|
||||||
public SuggestionBuilder(String name, String suggester) {
|
|
||||||
this.name = name;
|
|
||||||
this.suggester = suggester;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Same as in {@link SuggestBuilder#setText(String)}, but in the suggestion scope.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public T text(String text) {
|
|
||||||
this.text = text;
|
|
||||||
return (T) this;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setPrefix(String prefix) {
|
|
||||||
this.prefix = prefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setRegex(String regex) {
|
|
||||||
this.regex = regex;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
|
||||||
builder.startObject(name);
|
|
||||||
if (text != null) {
|
|
||||||
builder.field("text", text);
|
|
||||||
}
|
|
||||||
if (prefix != null) {
|
|
||||||
builder.field("prefix", prefix);
|
|
||||||
}
|
|
||||||
if (regex != null) {
|
|
||||||
builder.field("regex", regex);
|
|
||||||
}
|
|
||||||
builder.startObject(suggester);
|
|
||||||
if (analyzer != null) {
|
|
||||||
builder.field("analyzer", analyzer);
|
|
||||||
}
|
|
||||||
if (field != null) {
|
|
||||||
builder.field("field", field);
|
|
||||||
}
|
|
||||||
if (size != null) {
|
|
||||||
builder.field("size", size);
|
|
||||||
}
|
|
||||||
if (shardSize != null) {
|
|
||||||
builder.field("shard_size", shardSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
builder = innerToXContent(builder, params);
|
|
||||||
builder.endObject();
|
|
||||||
builder.endObject();
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract XContentBuilder innerToXContent(XContentBuilder builder, Params params) throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets from what field to fetch the candidate suggestions from. This is an
|
|
||||||
* required option and needs to be set via this setter or
|
|
||||||
* {@link org.elasticsearch.search.suggest.term.TermSuggestionBuilder#field(String)}
|
|
||||||
* method
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public T field(String field) {
|
|
||||||
this.field = field;
|
|
||||||
return (T)this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the analyzer to analyse to suggest text with. Defaults to the search
|
|
||||||
* analyzer of the suggest field.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public T analyzer(String analyzer) {
|
|
||||||
this.analyzer = analyzer;
|
|
||||||
return (T)this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the maximum suggestions to be returned per suggest text term.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public T size(int size) {
|
|
||||||
if (size <= 0) {
|
|
||||||
throw new IllegalArgumentException("Size must be positive");
|
|
||||||
}
|
|
||||||
this.size = size;
|
|
||||||
return (T)this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the maximum number of suggested term to be retrieved from each
|
|
||||||
* individual shard. During the reduce phase the only the top N suggestions
|
|
||||||
* are returned based on the <code>size</code> option. Defaults to the
|
|
||||||
* <code>size</code> option.
|
|
||||||
* <p>
|
|
||||||
* Setting this to a value higher than the `size` can be useful in order to
|
|
||||||
* get a more accurate document frequency for suggested terms. Due to the
|
|
||||||
* fact that terms are partitioned amongst shards, the shard level document
|
|
||||||
* frequencies of suggestions may not be precise. Increasing this will make
|
|
||||||
* these document frequencies more precise.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public T shardSize(Integer shardSize) {
|
|
||||||
this.shardSize = shardSize;
|
|
||||||
return (T)this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,299 @@
|
||||||
|
/*
|
||||||
|
* 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.elasticsearch.search.suggest;
|
||||||
|
|
||||||
|
import org.elasticsearch.action.support.ToXContentToBytes;
|
||||||
|
import org.elasticsearch.common.ParseField;
|
||||||
|
import org.elasticsearch.common.io.stream.NamedWriteable;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for the different suggestion implementations.
|
||||||
|
*/
|
||||||
|
public abstract class SuggestionBuilder<T extends SuggestionBuilder<T>> extends ToXContentToBytes implements NamedWriteable<T> {
|
||||||
|
|
||||||
|
protected final String name;
|
||||||
|
// TODO this seems mandatory and should be constructor arg
|
||||||
|
protected String fieldname;
|
||||||
|
protected String text;
|
||||||
|
protected String prefix;
|
||||||
|
protected String regex;
|
||||||
|
protected String analyzer;
|
||||||
|
protected Integer size;
|
||||||
|
protected Integer shardSize;
|
||||||
|
|
||||||
|
protected static final ParseField TEXT_FIELD = new ParseField("text");
|
||||||
|
protected static final ParseField PREFIX_FIELD = new ParseField("prefix");
|
||||||
|
protected static final ParseField REGEX_FIELD = new ParseField("regex");
|
||||||
|
protected static final ParseField FIELDNAME_FIELD = new ParseField("field");
|
||||||
|
protected static final ParseField ANALYZER_FIELD = new ParseField("analyzer");
|
||||||
|
protected static final ParseField SIZE_FIELD = new ParseField("size");
|
||||||
|
protected static final ParseField SHARDSIZE_FIELD = new ParseField("shard_size");
|
||||||
|
|
||||||
|
public SuggestionBuilder(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the name for this suggestion
|
||||||
|
*/
|
||||||
|
public String name() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as in {@link SuggestBuilder#setText(String)}, but in the suggestion scope.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public T text(String text) {
|
||||||
|
this.text = text;
|
||||||
|
return (T) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the text for this suggestion
|
||||||
|
*/
|
||||||
|
public String text() {
|
||||||
|
return this.text;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected T prefix(String prefix) {
|
||||||
|
this.prefix = prefix;
|
||||||
|
return (T) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the prefix for this suggestion
|
||||||
|
*/
|
||||||
|
public String prefix() {
|
||||||
|
return this.prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected T regex(String regex) {
|
||||||
|
this.regex = regex;
|
||||||
|
return (T) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the regex for this suggestion
|
||||||
|
*/
|
||||||
|
public String regex() {
|
||||||
|
return this.regex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.startObject(name);
|
||||||
|
if (text != null) {
|
||||||
|
builder.field(TEXT_FIELD.getPreferredName(), text);
|
||||||
|
}
|
||||||
|
if (prefix != null) {
|
||||||
|
builder.field(PREFIX_FIELD.getPreferredName(), prefix);
|
||||||
|
}
|
||||||
|
if (regex != null) {
|
||||||
|
builder.field(REGEX_FIELD.getPreferredName(), regex);
|
||||||
|
}
|
||||||
|
builder.startObject(getSuggesterName());
|
||||||
|
if (analyzer != null) {
|
||||||
|
builder.field(ANALYZER_FIELD.getPreferredName(), analyzer);
|
||||||
|
}
|
||||||
|
if (fieldname != null) {
|
||||||
|
builder.field(FIELDNAME_FIELD.getPreferredName(), fieldname);
|
||||||
|
}
|
||||||
|
if (size != null) {
|
||||||
|
builder.field(SIZE_FIELD.getPreferredName(), size);
|
||||||
|
}
|
||||||
|
if (shardSize != null) {
|
||||||
|
builder.field(SHARDSIZE_FIELD.getPreferredName(), shardSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder = innerToXContent(builder, params);
|
||||||
|
builder.endObject();
|
||||||
|
builder.endObject();
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSuggesterName() {
|
||||||
|
//default impl returns the same as writeable name, but we keep the distinction between the two just to make sure
|
||||||
|
return getWriteableName();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract XContentBuilder innerToXContent(XContentBuilder builder, Params params) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets from what field to fetch the candidate suggestions from. This is an
|
||||||
|
* required option and needs to be set via this setter or
|
||||||
|
* {@link org.elasticsearch.search.suggest.term.TermSuggestionBuilder#field(String)}
|
||||||
|
* method
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public T field(String field) {
|
||||||
|
this.fieldname = field;
|
||||||
|
return (T)this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the {@link #field()} parameter
|
||||||
|
*/
|
||||||
|
public String field() {
|
||||||
|
return this.fieldname;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the analyzer to analyse to suggest text with. Defaults to the search
|
||||||
|
* analyzer of the suggest field.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public T analyzer(String analyzer) {
|
||||||
|
this.analyzer = analyzer;
|
||||||
|
return (T)this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the {@link #analyzer()} parameter
|
||||||
|
*/
|
||||||
|
public String analyzer() {
|
||||||
|
return this.analyzer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the maximum suggestions to be returned per suggest text term.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public T size(int size) {
|
||||||
|
if (size <= 0) {
|
||||||
|
throw new IllegalArgumentException("Size must be positive");
|
||||||
|
}
|
||||||
|
this.size = size;
|
||||||
|
return (T)this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the {@link #size()} parameter
|
||||||
|
*/
|
||||||
|
public Integer size() {
|
||||||
|
return this.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the maximum number of suggested term to be retrieved from each
|
||||||
|
* individual shard. During the reduce phase the only the top N suggestions
|
||||||
|
* are returned based on the <code>size</code> option. Defaults to the
|
||||||
|
* <code>size</code> option.
|
||||||
|
* <p>
|
||||||
|
* Setting this to a value higher than the `size` can be useful in order to
|
||||||
|
* get a more accurate document frequency for suggested terms. Due to the
|
||||||
|
* fact that terms are partitioned amongst shards, the shard level document
|
||||||
|
* frequencies of suggestions may not be precise. Increasing this will make
|
||||||
|
* these document frequencies more precise.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public T shardSize(Integer shardSize) {
|
||||||
|
this.shardSize = shardSize;
|
||||||
|
return (T)this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the {@link #shardSize()} parameter
|
||||||
|
*/
|
||||||
|
public Integer shardSize() {
|
||||||
|
return this.shardSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final T readFrom(StreamInput in) throws IOException {
|
||||||
|
String name = in.readString();
|
||||||
|
T suggestionBuilder = doReadFrom(in, name);
|
||||||
|
suggestionBuilder.fieldname = in.readOptionalString();
|
||||||
|
suggestionBuilder.text = in.readOptionalString();
|
||||||
|
suggestionBuilder.prefix = in.readOptionalString();
|
||||||
|
suggestionBuilder.regex = in.readOptionalString();
|
||||||
|
suggestionBuilder.analyzer = in.readOptionalString();
|
||||||
|
suggestionBuilder.size = in.readOptionalVInt();
|
||||||
|
suggestionBuilder.shardSize = in.readOptionalVInt();
|
||||||
|
return suggestionBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclass should return a new instance, reading itself from the input string
|
||||||
|
* @param in the input string to read from
|
||||||
|
* @param name the name of the suggestion (read from stream by {@link SuggestionBuilder}
|
||||||
|
*/
|
||||||
|
protected abstract T doReadFrom(StreamInput in, String name) throws IOException;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void writeTo(StreamOutput out) throws IOException {
|
||||||
|
out.writeString(name);
|
||||||
|
doWriteTo(out);
|
||||||
|
out.writeOptionalString(fieldname);
|
||||||
|
out.writeOptionalString(text);
|
||||||
|
out.writeOptionalString(prefix);
|
||||||
|
out.writeOptionalString(regex);
|
||||||
|
out.writeOptionalString(analyzer);
|
||||||
|
out.writeOptionalVInt(size);
|
||||||
|
out.writeOptionalVInt(shardSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void doWriteTo(StreamOutput out) throws IOException;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null || getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
T other = (T) obj;
|
||||||
|
return Objects.equals(name, other.name()) &&
|
||||||
|
Objects.equals(text, other.text()) &&
|
||||||
|
Objects.equals(prefix, other.prefix()) &&
|
||||||
|
Objects.equals(regex, other.regex()) &&
|
||||||
|
Objects.equals(fieldname, other.field()) &&
|
||||||
|
Objects.equals(analyzer, other.analyzer()) &&
|
||||||
|
Objects.equals(size, other.size()) &&
|
||||||
|
Objects.equals(shardSize, other.shardSize()) &&
|
||||||
|
doEquals(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether some other {@link SuggestionBuilder} of the same type is "equal to" this one.
|
||||||
|
*/
|
||||||
|
protected abstract boolean doEquals(T other);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int hashCode() {
|
||||||
|
return Objects.hash(name, text, prefix, regex, fieldname, analyzer, size, shardSize, doHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HashCode for the subclass of {@link SuggestionBuilder} to implement.
|
||||||
|
*/
|
||||||
|
protected abstract int doHashCode();
|
||||||
|
}
|
|
@ -22,11 +22,13 @@ import org.apache.lucene.search.suggest.document.FuzzyCompletionQuery;
|
||||||
import org.apache.lucene.util.automaton.Operations;
|
import org.apache.lucene.util.automaton.Operations;
|
||||||
import org.apache.lucene.util.automaton.RegExp;
|
import org.apache.lucene.util.automaton.RegExp;
|
||||||
import org.elasticsearch.common.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.unit.Fuzziness;
|
import org.elasticsearch.common.unit.Fuzziness;
|
||||||
import org.elasticsearch.common.xcontent.ToXContent;
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.index.query.RegexpFlag;
|
import org.elasticsearch.index.query.RegexpFlag;
|
||||||
import org.elasticsearch.search.suggest.SuggestBuilder;
|
import org.elasticsearch.search.suggest.SuggestionBuilder;
|
||||||
import org.elasticsearch.search.suggest.completion.context.CategoryQueryContext;
|
import org.elasticsearch.search.suggest.completion.context.CategoryQueryContext;
|
||||||
import org.elasticsearch.search.suggest.completion.context.GeoQueryContext;
|
import org.elasticsearch.search.suggest.completion.context.GeoQueryContext;
|
||||||
|
|
||||||
|
@ -45,7 +47,7 @@ import java.util.Set;
|
||||||
* are created at index-time and so must be defined in the mapping with the type "completion" before
|
* are created at index-time and so must be defined in the mapping with the type "completion" before
|
||||||
* indexing.
|
* indexing.
|
||||||
*/
|
*/
|
||||||
public class CompletionSuggestionBuilder extends SuggestBuilder.SuggestionBuilder<CompletionSuggestionBuilder> {
|
public class CompletionSuggestionBuilder extends SuggestionBuilder<CompletionSuggestionBuilder> {
|
||||||
|
|
||||||
final static String SUGGESTION_NAME = "completion";
|
final static String SUGGESTION_NAME = "completion";
|
||||||
static final ParseField PAYLOAD_FIELD = new ParseField("payload");
|
static final ParseField PAYLOAD_FIELD = new ParseField("payload");
|
||||||
|
@ -56,7 +58,7 @@ public class CompletionSuggestionBuilder extends SuggestBuilder.SuggestionBuilde
|
||||||
private final Set<String> payloadFields = new HashSet<>();
|
private final Set<String> payloadFields = new HashSet<>();
|
||||||
|
|
||||||
public CompletionSuggestionBuilder(String name) {
|
public CompletionSuggestionBuilder(String name) {
|
||||||
super(name, SUGGESTION_NAME);
|
super(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -255,8 +257,9 @@ public class CompletionSuggestionBuilder extends SuggestBuilder.SuggestionBuilde
|
||||||
* Sets the prefix to provide completions for.
|
* Sets the prefix to provide completions for.
|
||||||
* The prefix gets analyzed by the suggest analyzer.
|
* The prefix gets analyzed by the suggest analyzer.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public CompletionSuggestionBuilder prefix(String prefix) {
|
public CompletionSuggestionBuilder prefix(String prefix) {
|
||||||
super.setPrefix(prefix);
|
super.prefix(prefix);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,7 +267,7 @@ public class CompletionSuggestionBuilder extends SuggestBuilder.SuggestionBuilde
|
||||||
* Same as {@link #prefix(String)} with fuzziness of <code>fuzziness</code>
|
* Same as {@link #prefix(String)} with fuzziness of <code>fuzziness</code>
|
||||||
*/
|
*/
|
||||||
public CompletionSuggestionBuilder prefix(String prefix, Fuzziness fuzziness) {
|
public CompletionSuggestionBuilder prefix(String prefix, Fuzziness fuzziness) {
|
||||||
super.setPrefix(prefix);
|
super.prefix(prefix);
|
||||||
this.fuzzyOptionsBuilder = new FuzzyOptionsBuilder().setFuzziness(fuzziness);
|
this.fuzzyOptionsBuilder = new FuzzyOptionsBuilder().setFuzziness(fuzziness);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -274,7 +277,7 @@ public class CompletionSuggestionBuilder extends SuggestBuilder.SuggestionBuilde
|
||||||
* see {@link FuzzyOptionsBuilder}
|
* see {@link FuzzyOptionsBuilder}
|
||||||
*/
|
*/
|
||||||
public CompletionSuggestionBuilder prefix(String prefix, FuzzyOptionsBuilder fuzzyOptionsBuilder) {
|
public CompletionSuggestionBuilder prefix(String prefix, FuzzyOptionsBuilder fuzzyOptionsBuilder) {
|
||||||
super.setPrefix(prefix);
|
super.prefix(prefix);
|
||||||
this.fuzzyOptionsBuilder = fuzzyOptionsBuilder;
|
this.fuzzyOptionsBuilder = fuzzyOptionsBuilder;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -282,8 +285,9 @@ public class CompletionSuggestionBuilder extends SuggestBuilder.SuggestionBuilde
|
||||||
/**
|
/**
|
||||||
* Sets a regular expression pattern for prefixes to provide completions for.
|
* Sets a regular expression pattern for prefixes to provide completions for.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public CompletionSuggestionBuilder regex(String regex) {
|
public CompletionSuggestionBuilder regex(String regex) {
|
||||||
super.setRegex(regex);
|
super.regex(regex);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,4 +366,33 @@ public class CompletionSuggestionBuilder extends SuggestBuilder.SuggestionBuilde
|
||||||
}
|
}
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getWriteableName() {
|
||||||
|
return SUGGESTION_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doWriteTo(StreamOutput out) throws IOException {
|
||||||
|
// NORELEASE
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletionSuggestionBuilder doReadFrom(StreamInput in, String name) throws IOException {
|
||||||
|
// NORELEASE
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean doEquals(CompletionSuggestionBuilder other) {
|
||||||
|
// NORELEASE
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int doHashCode() {
|
||||||
|
// NORELEASE
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,10 +18,12 @@
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.search.suggest.phrase;
|
package org.elasticsearch.search.suggest.phrase;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.xcontent.ToXContent;
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.script.Template;
|
import org.elasticsearch.script.Template;
|
||||||
import org.elasticsearch.search.suggest.SuggestBuilder.SuggestionBuilder;
|
import org.elasticsearch.search.suggest.SuggestionBuilder;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -29,12 +31,18 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the actual suggest command for phrase suggestions ( <tt>phrase</tt>).
|
* Defines the actual suggest command for phrase suggestions ( <tt>phrase</tt>).
|
||||||
*/
|
*/
|
||||||
public final class PhraseSuggestionBuilder extends SuggestionBuilder<PhraseSuggestionBuilder> {
|
public final class PhraseSuggestionBuilder extends SuggestionBuilder<PhraseSuggestionBuilder> {
|
||||||
|
|
||||||
|
static final String SUGGESTION_NAME = "phrase";
|
||||||
|
|
||||||
|
public static final PhraseSuggestionBuilder PROTOTYPE = new PhraseSuggestionBuilder("_na_");
|
||||||
|
|
||||||
private Float maxErrors;
|
private Float maxErrors;
|
||||||
private String separator;
|
private String separator;
|
||||||
private Float realWordErrorLikelihood;
|
private Float realWordErrorLikelihood;
|
||||||
|
@ -51,7 +59,7 @@ public final class PhraseSuggestionBuilder extends SuggestionBuilder<PhraseSugge
|
||||||
private Boolean collatePrune;
|
private Boolean collatePrune;
|
||||||
|
|
||||||
public PhraseSuggestionBuilder(String name) {
|
public PhraseSuggestionBuilder(String name) {
|
||||||
super(name, "phrase");
|
super(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,6 +75,13 @@ public final class PhraseSuggestionBuilder extends SuggestionBuilder<PhraseSugge
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the {@link #gramSize(int)} parameter
|
||||||
|
*/
|
||||||
|
public Integer gramSize() {
|
||||||
|
return this.gramSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the maximum percentage of the terms that at most considered to be
|
* Sets the maximum percentage of the terms that at most considered to be
|
||||||
* misspellings in order to form a correction. This method accepts a float
|
* misspellings in order to form a correction. This method accepts a float
|
||||||
|
@ -81,6 +96,13 @@ public final class PhraseSuggestionBuilder extends SuggestionBuilder<PhraseSugge
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the maxErrors setting
|
||||||
|
*/
|
||||||
|
public Float maxErrors() {
|
||||||
|
return this.maxErrors;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the separator that is used to separate terms in the bigram field. If
|
* Sets the separator that is used to separate terms in the bigram field. If
|
||||||
* not set the whitespace character is used as a separator.
|
* not set the whitespace character is used as a separator.
|
||||||
|
@ -90,6 +112,13 @@ public final class PhraseSuggestionBuilder extends SuggestionBuilder<PhraseSugge
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the separator that is used to separate terms in the bigram field.
|
||||||
|
*/
|
||||||
|
public String separator() {
|
||||||
|
return this.separator;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the likelihood of a term being a misspelled even if the term exists
|
* Sets the likelihood of a term being a misspelled even if the term exists
|
||||||
* in the dictionary. The default it <tt>0.95</tt> corresponding to 5% or
|
* in the dictionary. The default it <tt>0.95</tt> corresponding to 5% or
|
||||||
|
@ -100,6 +129,13 @@ public final class PhraseSuggestionBuilder extends SuggestionBuilder<PhraseSugge
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the {@link #realWordErrorLikelihood(Float)} parameter
|
||||||
|
*/
|
||||||
|
public Float realWordErrorLikelihood() {
|
||||||
|
return this.realWordErrorLikelihood;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the confidence level for this suggester. The confidence level
|
* Sets the confidence level for this suggester. The confidence level
|
||||||
* defines a factor applied to the input phrases score which is used as a
|
* defines a factor applied to the input phrases score which is used as a
|
||||||
|
@ -114,6 +150,13 @@ public final class PhraseSuggestionBuilder extends SuggestionBuilder<PhraseSugge
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the {@link #confidence()} parameter
|
||||||
|
*/
|
||||||
|
public Float confidence() {
|
||||||
|
return this.confidence;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a {@link CandidateGenerator} to this suggester. The
|
* Adds a {@link CandidateGenerator} to this suggester. The
|
||||||
* {@link CandidateGenerator} is used to draw candidates for each individual
|
* {@link CandidateGenerator} is used to draw candidates for each individual
|
||||||
|
@ -146,6 +189,13 @@ public final class PhraseSuggestionBuilder extends SuggestionBuilder<PhraseSugge
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the setting for {@link #forceUnigrams()}
|
||||||
|
*/
|
||||||
|
public Boolean forceUnigrams() {
|
||||||
|
return this.forceUnigrams;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets an explicit smoothing model used for this suggester. The default is
|
* Sets an explicit smoothing model used for this suggester. The default is
|
||||||
* {@link PhraseSuggestionBuilder.StupidBackoff}.
|
* {@link PhraseSuggestionBuilder.StupidBackoff}.
|
||||||
|
@ -160,6 +210,13 @@ public final class PhraseSuggestionBuilder extends SuggestionBuilder<PhraseSugge
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the {@link #tokenLimit(int)} parameter
|
||||||
|
*/
|
||||||
|
public Integer tokenLimit() {
|
||||||
|
return this.tokenLimit;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup highlighting for suggestions. If this is called a highlight field
|
* Setup highlighting for suggestions. If this is called a highlight field
|
||||||
* is returned with suggestions wrapping changed tokens with preTag and postTag.
|
* is returned with suggestions wrapping changed tokens with preTag and postTag.
|
||||||
|
@ -173,6 +230,20 @@ public final class PhraseSuggestionBuilder extends SuggestionBuilder<PhraseSugge
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the pre-tag for the highlighter set with {@link #highlight(String, String)}
|
||||||
|
*/
|
||||||
|
public String preTag() {
|
||||||
|
return this.preTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the post-tag for the highlighter set with {@link #highlight(String, String)}
|
||||||
|
*/
|
||||||
|
public String postTag() {
|
||||||
|
return this.postTag;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a query used for filtering out suggested phrases (collation).
|
* Sets a query used for filtering out suggested phrases (collation).
|
||||||
*/
|
*/
|
||||||
|
@ -189,6 +260,13 @@ public final class PhraseSuggestionBuilder extends SuggestionBuilder<PhraseSugge
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets the query used for filtering out suggested phrases (collation).
|
||||||
|
*/
|
||||||
|
public Template collateQuery() {
|
||||||
|
return this.collateQuery;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets additional params for collate script
|
* Sets additional params for collate script
|
||||||
*/
|
*/
|
||||||
|
@ -197,6 +275,13 @@ public final class PhraseSuggestionBuilder extends SuggestionBuilder<PhraseSugge
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets additional params for collate script
|
||||||
|
*/
|
||||||
|
public Map<String, Object> collateParams() {
|
||||||
|
return this.collateParams;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether to prune suggestions after collation
|
* Sets whether to prune suggestions after collation
|
||||||
*/
|
*/
|
||||||
|
@ -205,6 +290,13 @@ public final class PhraseSuggestionBuilder extends SuggestionBuilder<PhraseSugge
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether to prune suggestions after collation
|
||||||
|
*/
|
||||||
|
public Boolean collatePrune() {
|
||||||
|
return this.collatePrune;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public XContentBuilder innerToXContent(XContentBuilder builder, Params params) throws IOException {
|
public XContentBuilder innerToXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
if (realWordErrorLikelihood != null) {
|
if (realWordErrorLikelihood != null) {
|
||||||
|
@ -428,7 +520,7 @@ public final class PhraseSuggestionBuilder extends SuggestionBuilder<PhraseSugge
|
||||||
private Float minDocFreq;
|
private Float minDocFreq;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param field Sets from what field to fetch the candidate suggestions from.
|
* @param field Sets from what field to fetch the candidate suggestions from.
|
||||||
*/
|
*/
|
||||||
public DirectCandidateGenerator(String field) {
|
public DirectCandidateGenerator(String field) {
|
||||||
super("direct_generator");
|
super("direct_generator");
|
||||||
|
@ -655,4 +747,82 @@ public final class PhraseSuggestionBuilder extends SuggestionBuilder<PhraseSugge
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getWriteableName() {
|
||||||
|
return SUGGESTION_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doWriteTo(StreamOutput out) throws IOException {
|
||||||
|
out.writeOptionalFloat(maxErrors);
|
||||||
|
out.writeOptionalFloat(realWordErrorLikelihood);
|
||||||
|
out.writeOptionalFloat(confidence);
|
||||||
|
out.writeOptionalVInt(gramSize);
|
||||||
|
// NORELEASE model.writeTo();
|
||||||
|
out.writeOptionalBoolean(forceUnigrams);
|
||||||
|
out.writeOptionalVInt(tokenLimit);
|
||||||
|
out.writeOptionalString(preTag);
|
||||||
|
out.writeOptionalString(postTag);
|
||||||
|
out.writeOptionalString(separator);
|
||||||
|
if (collateQuery != null) {
|
||||||
|
out.writeBoolean(true);
|
||||||
|
collateQuery.writeTo(out);
|
||||||
|
} else {
|
||||||
|
out.writeBoolean(false);
|
||||||
|
}
|
||||||
|
out.writeMap(collateParams);
|
||||||
|
out.writeOptionalBoolean(collatePrune);
|
||||||
|
// NORELEASE write Map<String, List<CandidateGenerator>> generators = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PhraseSuggestionBuilder doReadFrom(StreamInput in, String name) throws IOException {
|
||||||
|
PhraseSuggestionBuilder builder = new PhraseSuggestionBuilder(name);
|
||||||
|
builder.maxErrors = in.readOptionalFloat();
|
||||||
|
builder.realWordErrorLikelihood = in.readOptionalFloat();
|
||||||
|
builder.confidence = in.readOptionalFloat();
|
||||||
|
builder.gramSize = in.readOptionalVInt();
|
||||||
|
// NORELEASE read model
|
||||||
|
builder.forceUnigrams = in.readOptionalBoolean();
|
||||||
|
builder.tokenLimit = in.readOptionalVInt();
|
||||||
|
builder.preTag = in.readOptionalString();
|
||||||
|
builder.postTag = in.readOptionalString();
|
||||||
|
builder.separator = in.readOptionalString();
|
||||||
|
if (in.readBoolean()) {
|
||||||
|
builder.collateQuery = Template.readTemplate(in);
|
||||||
|
}
|
||||||
|
builder.collateParams = in.readMap();
|
||||||
|
builder.collatePrune = in.readOptionalBoolean();
|
||||||
|
// NORELEASE read Map<String, List<CandidateGenerator>> generators;
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean doEquals(PhraseSuggestionBuilder other) {
|
||||||
|
return Objects.equals(maxErrors, other.maxErrors) &&
|
||||||
|
Objects.equals(separator, other.separator) &&
|
||||||
|
Objects.equals(realWordErrorLikelihood, other.realWordErrorLikelihood) &&
|
||||||
|
Objects.equals(confidence, other.confidence) &&
|
||||||
|
// NORELEASE Objects.equals(generator, other.generator) &&
|
||||||
|
Objects.equals(gramSize, other.gramSize) &&
|
||||||
|
// NORELEASE Objects.equals(model, other.model) &&
|
||||||
|
Objects.equals(forceUnigrams, other.forceUnigrams) &&
|
||||||
|
Objects.equals(tokenLimit, other.tokenLimit) &&
|
||||||
|
Objects.equals(preTag, other.preTag) &&
|
||||||
|
Objects.equals(postTag, other.postTag) &&
|
||||||
|
Objects.equals(collateQuery, other.collateQuery) &&
|
||||||
|
Objects.equals(collateParams, other.collateParams) &&
|
||||||
|
Objects.equals(collatePrune, other.collatePrune);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int doHashCode() {
|
||||||
|
return Objects.hash(maxErrors, separator, realWordErrorLikelihood, confidence,
|
||||||
|
/** NORELEASE generators, */
|
||||||
|
gramSize,
|
||||||
|
/** NORELEASE model, */
|
||||||
|
forceUnigrams, tokenLimit, preTag, postTag,
|
||||||
|
collateQuery, collateParams, collatePrune);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,10 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.search.suggest.term;
|
package org.elasticsearch.search.suggest.term;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.search.suggest.SuggestBuilder.SuggestionBuilder;
|
import org.elasticsearch.search.suggest.SuggestionBuilder;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@ -29,6 +31,8 @@ import java.io.IOException;
|
||||||
*/
|
*/
|
||||||
public class TermSuggestionBuilder extends SuggestionBuilder<TermSuggestionBuilder> {
|
public class TermSuggestionBuilder extends SuggestionBuilder<TermSuggestionBuilder> {
|
||||||
|
|
||||||
|
static final String SUGGESTION_NAME = "term";
|
||||||
|
|
||||||
private String suggestMode;
|
private String suggestMode;
|
||||||
private Float accuracy;
|
private Float accuracy;
|
||||||
private String sort;
|
private String sort;
|
||||||
|
@ -39,13 +43,13 @@ public class TermSuggestionBuilder extends SuggestionBuilder<TermSuggestionBuild
|
||||||
private Integer prefixLength;
|
private Integer prefixLength;
|
||||||
private Integer minWordLength;
|
private Integer minWordLength;
|
||||||
private Float minDocFreq;
|
private Float minDocFreq;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param name
|
* @param name
|
||||||
* The name of this suggestion. This is a required parameter.
|
* The name of this suggestion. This is a required parameter.
|
||||||
*/
|
*/
|
||||||
public TermSuggestionBuilder(String name) {
|
public TermSuggestionBuilder(String name) {
|
||||||
super(name, "term");
|
super(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -221,4 +225,33 @@ public class TermSuggestionBuilder extends SuggestionBuilder<TermSuggestionBuild
|
||||||
}
|
}
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getWriteableName() {
|
||||||
|
return SUGGESTION_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doWriteTo(StreamOutput out) throws IOException {
|
||||||
|
// NORELEASE
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TermSuggestionBuilder doReadFrom(StreamInput in, String name) throws IOException {
|
||||||
|
// NORELEASE
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean doEquals(TermSuggestionBuilder other) {
|
||||||
|
// NORELEASE
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int doHashCode() {
|
||||||
|
// NORELEASE
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,186 @@
|
||||||
|
/*
|
||||||
|
* 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.elasticsearch.search.suggest;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.io.stream.BytesStreamOutput;
|
||||||
|
import org.elasticsearch.common.io.stream.NamedWriteableAwareStreamInput;
|
||||||
|
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
import org.elasticsearch.search.suggest.phrase.PhraseSuggestionBuilder;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.not;
|
||||||
|
|
||||||
|
public abstract class AbstractSuggestionBuilderTestCase<SB extends SuggestionBuilder<SB>> extends ESTestCase {
|
||||||
|
|
||||||
|
private static final int NUMBER_OF_TESTBUILDERS = 20;
|
||||||
|
private static NamedWriteableRegistry namedWriteableRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setup for the whole base test class
|
||||||
|
*/
|
||||||
|
@BeforeClass
|
||||||
|
public static void init() {
|
||||||
|
namedWriteableRegistry = new NamedWriteableRegistry();
|
||||||
|
namedWriteableRegistry.registerPrototype(SuggestionBuilder.class, PhraseSuggestionBuilder.PROTOTYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClass() throws Exception {
|
||||||
|
namedWriteableRegistry = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test serialization and deserialization of the suggestion builder
|
||||||
|
*/
|
||||||
|
public void testSerialization() throws IOException {
|
||||||
|
for (int runs = 0; runs < NUMBER_OF_TESTBUILDERS; runs++) {
|
||||||
|
SB original = randomTestBuilder();
|
||||||
|
SB deserialized = serializedCopy(original);
|
||||||
|
assertEquals(deserialized, original);
|
||||||
|
assertEquals(deserialized.hashCode(), original.hashCode());
|
||||||
|
assertNotSame(deserialized, original);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns a random suggestion builder, setting the common options randomly
|
||||||
|
*/
|
||||||
|
protected SB randomTestBuilder() {
|
||||||
|
SB randomSuggestion = randomSuggestionBuilder();
|
||||||
|
maybeSet(randomSuggestion::text, randomAsciiOfLengthBetween(2, 20));
|
||||||
|
maybeSet(randomSuggestion::prefix, randomAsciiOfLengthBetween(2, 20));
|
||||||
|
maybeSet(randomSuggestion::regex, randomAsciiOfLengthBetween(2, 20));
|
||||||
|
maybeSet(randomSuggestion::field, randomAsciiOfLengthBetween(2, 20));
|
||||||
|
maybeSet(randomSuggestion::analyzer, randomAsciiOfLengthBetween(2, 20));
|
||||||
|
maybeSet(randomSuggestion::size, randomIntBetween(1, 20));
|
||||||
|
maybeSet(randomSuggestion::shardSize, randomInt(20));
|
||||||
|
return randomSuggestion;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create a randomized {@link SuggestBuilder} that is used in further tests
|
||||||
|
*/
|
||||||
|
protected abstract SB randomSuggestionBuilder();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test equality and hashCode properties
|
||||||
|
*/
|
||||||
|
public void testEqualsAndHashcode() throws IOException {
|
||||||
|
for (int runs = 0; runs < NUMBER_OF_TESTBUILDERS; runs++) {
|
||||||
|
SB firstBuilder = randomTestBuilder();
|
||||||
|
assertFalse("suggestion builder is equal to null", firstBuilder.equals(null));
|
||||||
|
assertFalse("suggestion builder is equal to incompatible type", firstBuilder.equals(""));
|
||||||
|
assertTrue("suggestion builder is not equal to self", firstBuilder.equals(firstBuilder));
|
||||||
|
assertThat("same suggestion builder's hashcode returns different values if called multiple times", firstBuilder.hashCode(),
|
||||||
|
equalTo(firstBuilder.hashCode()));
|
||||||
|
assertThat("different suggestion builders should not be equal", mutate(firstBuilder), not(equalTo(firstBuilder)));
|
||||||
|
|
||||||
|
SB secondBuilder = serializedCopy(firstBuilder);
|
||||||
|
assertTrue("suggestion builder is not equal to self", secondBuilder.equals(secondBuilder));
|
||||||
|
assertTrue("suggestion builder is not equal to its copy", firstBuilder.equals(secondBuilder));
|
||||||
|
assertTrue("equals is not symmetric", secondBuilder.equals(firstBuilder));
|
||||||
|
assertThat("suggestion builder copy's hashcode is different from original hashcode", secondBuilder.hashCode(), equalTo(firstBuilder.hashCode()));
|
||||||
|
|
||||||
|
SB thirdBuilder = serializedCopy(secondBuilder);
|
||||||
|
assertTrue("suggestion builder is not equal to self", thirdBuilder.equals(thirdBuilder));
|
||||||
|
assertTrue("suggestion builder is not equal to its copy", secondBuilder.equals(thirdBuilder));
|
||||||
|
assertThat("suggestion builder copy's hashcode is different from original hashcode", secondBuilder.hashCode(), equalTo(thirdBuilder.hashCode()));
|
||||||
|
assertTrue("equals is not transitive", firstBuilder.equals(thirdBuilder));
|
||||||
|
assertThat("suggestion builder copy's hashcode is different from original hashcode", firstBuilder.hashCode(), equalTo(thirdBuilder.hashCode()));
|
||||||
|
assertTrue("equals is not symmetric", thirdBuilder.equals(secondBuilder));
|
||||||
|
assertTrue("equals is not symmetric", thirdBuilder.equals(firstBuilder));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SB mutate(SB firstBuilder) throws IOException {
|
||||||
|
SB mutation = serializedCopy(firstBuilder);
|
||||||
|
assertNotSame(mutation, firstBuilder);
|
||||||
|
if (randomBoolean()) {
|
||||||
|
// change one of the common SuggestionBuilder parameters
|
||||||
|
switch (randomIntBetween(0, 6)) {
|
||||||
|
case 0:
|
||||||
|
mutation.text(randomValueOtherThan(mutation.text(), () -> randomAsciiOfLengthBetween(2, 20)));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
mutation.prefix(randomValueOtherThan(mutation.prefix(), () -> randomAsciiOfLengthBetween(2, 20)));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
mutation.regex(randomValueOtherThan(mutation.regex(), () -> randomAsciiOfLengthBetween(2, 20)));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
mutation.field(randomValueOtherThan(mutation.field(), () -> randomAsciiOfLengthBetween(2, 20)));
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
mutation.analyzer(randomValueOtherThan(mutation.analyzer(), () -> randomAsciiOfLengthBetween(2, 20)));
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
mutation.size(randomValueOtherThan(mutation.size(), () -> randomIntBetween(1, 20)));
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
mutation.shardSize(randomValueOtherThan(mutation.shardSize(), () -> randomIntBetween(1, 20)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mutateSpecificParameters(firstBuilder);
|
||||||
|
}
|
||||||
|
return mutation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* take and input {@link SuggestBuilder} and return another one that is different in one aspect (to test non-equality)
|
||||||
|
*/
|
||||||
|
protected abstract void mutateSpecificParameters(SB firstBuilder) throws IOException;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected SB serializedCopy(SB original) throws IOException {
|
||||||
|
try (BytesStreamOutput output = new BytesStreamOutput()) {
|
||||||
|
output.writeSuggestion(original);;
|
||||||
|
try (StreamInput in = new NamedWriteableAwareStreamInput(StreamInput.wrap(output.bytes()), namedWriteableRegistry)) {
|
||||||
|
return (SB) in.readSuggestion();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static <T> void maybeSet(Consumer<T> consumer, T value) {
|
||||||
|
if (randomBoolean()) {
|
||||||
|
consumer.accept(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* helper to get a random value in a certain range that's different from the input
|
||||||
|
*/
|
||||||
|
protected static <T> T randomValueOtherThan(T input, Supplier<T> randomSupplier) {
|
||||||
|
T randomValue = null;
|
||||||
|
do {
|
||||||
|
randomValue = randomSupplier.get();
|
||||||
|
} while (randomValue.equals(input));
|
||||||
|
return randomValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -20,6 +20,7 @@ package org.elasticsearch.search.suggest;
|
||||||
|
|
||||||
import com.carrotsearch.hppc.ObjectLongHashMap;
|
import com.carrotsearch.hppc.ObjectLongHashMap;
|
||||||
import com.carrotsearch.randomizedtesting.generators.RandomStrings;
|
import com.carrotsearch.randomizedtesting.generators.RandomStrings;
|
||||||
|
|
||||||
import org.apache.lucene.analysis.TokenStreamToAutomaton;
|
import org.apache.lucene.analysis.TokenStreamToAutomaton;
|
||||||
import org.apache.lucene.search.suggest.document.ContextSuggestField;
|
import org.apache.lucene.search.suggest.document.ContextSuggestField;
|
||||||
import org.apache.lucene.util.LuceneTestCase.SuppressCodecs;
|
import org.apache.lucene.util.LuceneTestCase.SuppressCodecs;
|
||||||
|
@ -907,7 +908,7 @@ public class CompletionSuggestSearchIT extends ESIntegTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void assertSuggestions(String suggestionName, SuggestBuilder.SuggestionBuilder suggestBuilder, String... suggestions) {
|
public void assertSuggestions(String suggestionName, SuggestionBuilder suggestBuilder, String... suggestions) {
|
||||||
SuggestResponse suggestResponse = client().prepareSuggest(INDEX).addSuggestion(suggestBuilder
|
SuggestResponse suggestResponse = client().prepareSuggest(INDEX).addSuggestion(suggestBuilder
|
||||||
).execute().actionGet();
|
).execute().actionGet();
|
||||||
assertSuggestions(suggestResponse, suggestionName, suggestions);
|
assertSuggestions(suggestResponse, suggestionName, suggestions);
|
||||||
|
|
|
@ -632,7 +632,7 @@ public class ContextCompletionSuggestSearchIT extends ESIntegTestCase {
|
||||||
assertEquals("Hotel Amsterdam in Berlin", suggestResponse.getSuggest().getSuggestion(suggestionName).iterator().next().getOptions().iterator().next().getText().string());
|
assertEquals("Hotel Amsterdam in Berlin", suggestResponse.getSuggest().getSuggestion(suggestionName).iterator().next().getOptions().iterator().next().getText().string());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assertSuggestions(String suggestionName, SuggestBuilder.SuggestionBuilder suggestBuilder, String... suggestions) {
|
public void assertSuggestions(String suggestionName, SuggestionBuilder suggestBuilder, String... suggestions) {
|
||||||
SuggestResponse suggestResponse = client().prepareSuggest(INDEX).addSuggestion(suggestBuilder
|
SuggestResponse suggestResponse = client().prepareSuggest(INDEX).addSuggestion(suggestBuilder
|
||||||
).execute().actionGet();
|
).execute().actionGet();
|
||||||
CompletionSuggestSearchIT.assertSuggestions(suggestResponse, suggestionName, suggestions);
|
CompletionSuggestSearchIT.assertSuggestions(suggestResponse, suggestionName, suggestions);
|
||||||
|
|
|
@ -20,6 +20,8 @@ package org.elasticsearch.search.suggest;
|
||||||
|
|
||||||
import org.elasticsearch.action.search.SearchRequestBuilder;
|
import org.elasticsearch.action.search.SearchRequestBuilder;
|
||||||
import org.elasticsearch.action.search.SearchResponse;
|
import org.elasticsearch.action.search.SearchResponse;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.util.CollectionUtils;
|
import org.elasticsearch.common.util.CollectionUtils;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.plugins.Plugin;
|
import org.elasticsearch.plugins.Plugin;
|
||||||
|
@ -31,6 +33,7 @@ import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||||
import static org.hamcrest.Matchers.hasSize;
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
|
@ -59,16 +62,7 @@ public class CustomSuggesterSearchIT extends ESIntegTestCase {
|
||||||
String randomField = randomAsciiOfLength(10);
|
String randomField = randomAsciiOfLength(10);
|
||||||
String randomSuffix = randomAsciiOfLength(10);
|
String randomSuffix = randomAsciiOfLength(10);
|
||||||
SuggestBuilder suggestBuilder = new SuggestBuilder();
|
SuggestBuilder suggestBuilder = new SuggestBuilder();
|
||||||
suggestBuilder.addSuggestion(
|
suggestBuilder.addSuggestion(new CustomSuggestionBuilder("someName", randomField, randomSuffix).text(randomText));
|
||||||
new SuggestBuilder.SuggestionBuilder<SuggestBuilder.SuggestionBuilder>("someName", "custom") {
|
|
||||||
@Override
|
|
||||||
protected XContentBuilder innerToXContent(XContentBuilder builder, Params params) throws IOException {
|
|
||||||
builder.field("field", randomField);
|
|
||||||
builder.field("suffix", randomSuffix);
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
}.text(randomText)
|
|
||||||
);
|
|
||||||
SearchRequestBuilder searchRequestBuilder = client().prepareSearch("test").setTypes("test").setFrom(0).setSize(1)
|
SearchRequestBuilder searchRequestBuilder = client().prepareSearch("test").setTypes("test").setFrom(0).setSize(1)
|
||||||
.suggest(suggestBuilder);
|
.suggest(suggestBuilder);
|
||||||
|
|
||||||
|
@ -83,4 +77,51 @@ public class CustomSuggesterSearchIT extends ESIntegTestCase {
|
||||||
assertThat(suggestions.get(1).getText().string(), is(String.format(Locale.ROOT, "%s-%s-%s-123", randomText, randomField, randomSuffix)));
|
assertThat(suggestions.get(1).getText().string(), is(String.format(Locale.ROOT, "%s-%s-%s-123", randomText, randomField, randomSuffix)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CustomSuggestionBuilder extends SuggestionBuilder<CustomSuggestionBuilder> {
|
||||||
|
|
||||||
|
private String randomField;
|
||||||
|
private String randomSuffix;
|
||||||
|
|
||||||
|
public CustomSuggestionBuilder(String name, String randomField, String randomSuffix) {
|
||||||
|
super(name);
|
||||||
|
this.randomField = randomField;
|
||||||
|
this.randomSuffix = randomSuffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected XContentBuilder innerToXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.field("field", randomField);
|
||||||
|
builder.field("suffix", randomSuffix);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getWriteableName() {
|
||||||
|
return "custom";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doWriteTo(StreamOutput out) throws IOException {
|
||||||
|
out.writeString(randomField);
|
||||||
|
out.writeString(randomSuffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CustomSuggestionBuilder doReadFrom(StreamInput in, String name) throws IOException {
|
||||||
|
return new CustomSuggestionBuilder(in.readString(), in.readString(), in.readString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean doEquals(CustomSuggestionBuilder other) {
|
||||||
|
return Objects.equals(randomField, other.randomField) &&
|
||||||
|
Objects.equals(randomSuffix, other.randomSuffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int doHashCode() {
|
||||||
|
return Objects.hash(randomField, randomSuffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
/*
|
||||||
|
* 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.elasticsearch.search.suggest.phrase;
|
||||||
|
|
||||||
|
import org.elasticsearch.script.Template;
|
||||||
|
import org.elasticsearch.search.suggest.AbstractSuggestionBuilderTestCase;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class PhraseSuggestionBuilderTests extends AbstractSuggestionBuilderTestCase<PhraseSuggestionBuilder> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PhraseSuggestionBuilder randomSuggestionBuilder() {
|
||||||
|
PhraseSuggestionBuilder testBuilder = new PhraseSuggestionBuilder(randomAsciiOfLength(10));
|
||||||
|
maybeSet(testBuilder::maxErrors, randomFloat());
|
||||||
|
maybeSet(testBuilder::separator, randomAsciiOfLengthBetween(1, 10));
|
||||||
|
maybeSet(testBuilder::realWordErrorLikelihood, randomFloat());
|
||||||
|
maybeSet(testBuilder::confidence, randomFloat());
|
||||||
|
maybeSet(testBuilder::collatePrune, randomBoolean());
|
||||||
|
maybeSet(testBuilder::collateQuery, randomAsciiOfLengthBetween(3, 20));
|
||||||
|
if (randomBoolean()) {
|
||||||
|
// preTag, postTag
|
||||||
|
testBuilder.highlight(randomAsciiOfLengthBetween(3, 20), randomAsciiOfLengthBetween(3, 20));
|
||||||
|
}
|
||||||
|
maybeSet(testBuilder::gramSize, randomIntBetween(1, 5));
|
||||||
|
maybeSet(testBuilder::forceUnigrams, randomBoolean());
|
||||||
|
maybeSet(testBuilder::tokenLimit, randomInt(20));
|
||||||
|
if (randomBoolean()) {
|
||||||
|
Map<String, Object> collateParams = new HashMap<>();
|
||||||
|
collateParams.put(randomAsciiOfLength(5), randomAsciiOfLength(5));
|
||||||
|
testBuilder.collateParams(collateParams );
|
||||||
|
}
|
||||||
|
if (randomBoolean()) {
|
||||||
|
// NORELEASE add random model
|
||||||
|
}
|
||||||
|
|
||||||
|
if (randomBoolean()) {
|
||||||
|
// NORELEASE add random generator
|
||||||
|
}
|
||||||
|
return testBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void mutateSpecificParameters(PhraseSuggestionBuilder builder) throws IOException {
|
||||||
|
switch (randomIntBetween(0, 7)) {
|
||||||
|
case 0:
|
||||||
|
builder.maxErrors(randomValueOtherThan(builder.maxErrors(), () -> randomFloat()));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
builder.realWordErrorLikelihood(randomValueOtherThan(builder.realWordErrorLikelihood(), () -> randomFloat()));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
builder.confidence(randomValueOtherThan(builder.confidence(), () -> randomFloat()));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
builder.gramSize(randomValueOtherThan(builder.gramSize(), () -> randomIntBetween(1, 5)));
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
builder.tokenLimit(randomValueOtherThan(builder.tokenLimit(), () -> randomInt(20)));
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
builder.separator(randomValueOtherThan(builder.separator(), () -> randomAsciiOfLengthBetween(1, 10)));
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
Template collateQuery = builder.collateQuery();
|
||||||
|
if (collateQuery != null) {
|
||||||
|
builder.collateQuery(randomValueOtherThan(collateQuery.getScript(), () -> randomAsciiOfLengthBetween(3, 20)));
|
||||||
|
} else {
|
||||||
|
builder.collateQuery(randomAsciiOfLengthBetween(3, 20));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
builder.collatePrune(builder.collatePrune() == null ? randomBoolean() : !builder.collatePrune() );
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
// preTag, postTag
|
||||||
|
String currentPre = builder.preTag();
|
||||||
|
if (currentPre != null) {
|
||||||
|
// simply double both values
|
||||||
|
builder.highlight(builder.preTag() + builder.preTag(), builder.postTag() + builder.postTag());
|
||||||
|
} else {
|
||||||
|
builder.highlight(randomAsciiOfLengthBetween(3, 20), randomAsciiOfLengthBetween(3, 20));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
builder.forceUnigrams(builder.forceUnigrams() == null ? randomBoolean() : ! builder.forceUnigrams());
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
builder.collateParams().put(randomAsciiOfLength(5), randomAsciiOfLength(5));
|
||||||
|
break;
|
||||||
|
// TODO mutate random Model && generator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -20,43 +20,6 @@
|
||||||
package org.elasticsearch.messy.tests;
|
package org.elasticsearch.messy.tests;
|
||||||
|
|
||||||
|
|
||||||
import org.elasticsearch.ElasticsearchException;
|
|
||||||
import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
|
|
||||||
import org.elasticsearch.action.index.IndexRequestBuilder;
|
|
||||||
import org.elasticsearch.action.search.ReduceSearchPhaseException;
|
|
||||||
import org.elasticsearch.action.search.SearchPhaseExecutionException;
|
|
||||||
import org.elasticsearch.action.search.SearchRequestBuilder;
|
|
||||||
import org.elasticsearch.action.search.SearchResponse;
|
|
||||||
import org.elasticsearch.action.search.ShardSearchFailure;
|
|
||||||
import org.elasticsearch.action.suggest.SuggestRequestBuilder;
|
|
||||||
import org.elasticsearch.action.suggest.SuggestResponse;
|
|
||||||
import org.elasticsearch.common.io.PathUtils;
|
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
|
||||||
import org.elasticsearch.plugins.Plugin;
|
|
||||||
import org.elasticsearch.script.mustache.MustachePlugin;
|
|
||||||
import org.elasticsearch.search.suggest.Suggest;
|
|
||||||
import org.elasticsearch.search.suggest.SuggestBuilder;
|
|
||||||
import org.elasticsearch.search.suggest.SuggestBuilder.SuggestionBuilder;
|
|
||||||
import org.elasticsearch.search.suggest.phrase.PhraseSuggestionBuilder;
|
|
||||||
import org.elasticsearch.search.suggest.phrase.PhraseSuggestionBuilder.DirectCandidateGenerator;
|
|
||||||
import org.elasticsearch.search.suggest.term.TermSuggestionBuilder;
|
|
||||||
import org.elasticsearch.test.ESIntegTestCase;
|
|
||||||
import org.elasticsearch.test.hamcrest.ElasticsearchAssertions;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
|
|
||||||
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_REPLICAS;
|
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_REPLICAS;
|
||||||
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_SHARDS;
|
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_SHARDS;
|
||||||
import static org.elasticsearch.common.settings.Settings.settingsBuilder;
|
import static org.elasticsearch.common.settings.Settings.settingsBuilder;
|
||||||
|
@ -76,6 +39,43 @@ import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.instanceOf;
|
import static org.hamcrest.Matchers.instanceOf;
|
||||||
import static org.hamcrest.Matchers.nullValue;
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticsearchException;
|
||||||
|
import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
|
||||||
|
import org.elasticsearch.action.index.IndexRequestBuilder;
|
||||||
|
import org.elasticsearch.action.search.ReduceSearchPhaseException;
|
||||||
|
import org.elasticsearch.action.search.SearchPhaseExecutionException;
|
||||||
|
import org.elasticsearch.action.search.SearchRequestBuilder;
|
||||||
|
import org.elasticsearch.action.search.SearchResponse;
|
||||||
|
import org.elasticsearch.action.search.ShardSearchFailure;
|
||||||
|
import org.elasticsearch.action.suggest.SuggestRequestBuilder;
|
||||||
|
import org.elasticsearch.action.suggest.SuggestResponse;
|
||||||
|
import org.elasticsearch.common.io.PathUtils;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||||
|
import org.elasticsearch.plugins.Plugin;
|
||||||
|
import org.elasticsearch.script.mustache.MustachePlugin;
|
||||||
|
import org.elasticsearch.search.suggest.Suggest;
|
||||||
|
import org.elasticsearch.search.suggest.SuggestBuilder;
|
||||||
|
import org.elasticsearch.search.suggest.SuggestionBuilder;
|
||||||
|
import org.elasticsearch.search.suggest.phrase.PhraseSuggestionBuilder;
|
||||||
|
import org.elasticsearch.search.suggest.phrase.PhraseSuggestionBuilder.DirectCandidateGenerator;
|
||||||
|
import org.elasticsearch.search.suggest.term.TermSuggestionBuilder;
|
||||||
|
import org.elasticsearch.test.ESIntegTestCase;
|
||||||
|
import org.elasticsearch.test.hamcrest.ElasticsearchAssertions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Integration tests for term and phrase suggestions. Many of these tests many requests that vary only slightly from one another. Where
|
* Integration tests for term and phrase suggestions. Many of these tests many requests that vary only slightly from one another. Where
|
||||||
* possible these tests should declare for the first request, make the request, modify the configuration for the next request, make that
|
* possible these tests should declare for the first request, make the request, modify the configuration for the next request, make that
|
||||||
|
|
Loading…
Reference in New Issue