Updated suggest api.
# Suggest feature The suggest feature suggests similar looking terms based on a provided text by using a suggester. At the moment there the only supported suggester is `fuzzy`. The suggest feature is available from version `0.21.0`. # Fuzzy suggester The `fuzzy` suggester suggests terms based on edit distance. The provided suggest text is analyzed before terms are suggested. The suggested terms are provided per analyzed suggest text token. The `fuzzy` suggester doesn't take the query into account that is part of request. # Suggest API The suggest request part is defined along side the query part as top field in the json request. ``` curl -s -XPOST 'localhost:9200/_search' -d '{ "query" : { ... }, "suggest" : { ... } }' ``` Several suggestions can be specified per request. Each suggestion is identified with an arbitary name. In the example below two suggestions are requested. Both `my-suggest-1` and `my-suggest-2` suggestions use the `fuzzy` suggester, but have a different `text`. ``` "suggest" : { "my-suggest-1" : { "text" : "the amsterdma meetpu", "fuzzy" : { "field" : "body" } }, "my-suggest-2" : { "text" : "the rottredam meetpu", "fuzzy" : { "field" : "title", } } } ``` The below suggest response example includes the suggestion response for `my-suggest-1` and `my-suggest-2`. Each suggestion part contains entries. Each entry is effectively a token from the suggest text and contains the suggestion entry text, the original start offset and length in the suggest text and if found an arbitary number of options. ``` { ... "suggest": { "my-suggest-1": [ { "text" : "amsterdma", "offset": 4, "length": 9, "options": [ ... ] }, ... ], "my-suggest-2" : [ ... ] } ... } ``` Each options array contains a option object that includes the suggested text, its document frequency and score compared to the suggest entry text. The meaning of the score depends on the used suggester. The fuzzy suggester's score is based on the edit distance. ``` "options": [ { "text": "amsterdam", "freq": 77, "score": 0.8888889 }, ... ] ``` # Global suggest text To avoid repitition of the suggest text, it is possible to define a global text. In the example below the suggest text is defined globally and applies to the `my-suggest-1` and `my-suggest-2` suggestions. ``` "suggest" : { "text" : "the amsterdma meetpu" "my-suggest-1" : { "fuzzy" : { "field" : "title" } }, "my-suggest-2" : { "fuzzy" : { "field" : "body" } } } ``` The suggest text can in the above example also be specied as suggestion specific option. The suggest text specified on suggestion level override the suggest text on the global level. # Other suggest example. In the below example we request suggestions for the following suggest text: `devloping distibutd saerch engies` on the `title` field with a maximum of 3 suggestions per term inside the suggest text. Note that in this example we use the `count` search type. This isn't required, but a nice optimalization. The suggestions are gather in the `query` phase and in the case that we only care about suggestions (so no hits) we don't need to execute the `fetch` phase. ``` curl -s -XPOST 'localhost:9200/_search?search_type=count' -d '{ "suggest" : { "my-title-suggestions-1" : { "text" : "devloping distibutd saerch engies", "fuzzy" : { "size" : 3, "field" : "title" } } } }' ``` The above request could yield the response as stated in the code example below. As you can see if we take the first suggested options of each suggestion entry we get `developing distributed search engines` as result. ``` { ... "suggest": { "my-title-suggestions-1": [ { "text": "devloping", "offset": 0, "length": 9, "options": [ { "text": "developing", "freq": 77, "score": 0.8888889 }, { "text": "deloping", "freq": 1, "score": 0.875 }, { "text": "deploying", "freq": 2, "score": 0.7777778 } ] }, { "text": "distibutd", "offset": 10, "length": 9, "options": [ { "text": "distributed", "freq": 217, "score": 0.7777778 }, { "text": "disributed", "freq": 1, "score": 0.7777778 }, { "text": "distribute", "freq": 1, "score": 0.7777778 } ] }, { "text": "saerch", "offset": 20, "length": 6, "options": [ { "text": "search", "freq": 1038, "score": 0.8333333 }, { "text": "smerch", "freq": 3, "score": 0.8333333 }, { "text": "serch", "freq": 2, "score": 0.8 } ] }, { "text": "engies", "offset": 27, "length": 6, "options": [ { "text": "engines", "freq": 568, "score": 0.8333333 }, { "text": "engles", "freq": 3, "score": 0.8333333 }, { "text": "eggies", "freq": 1, "score": 0.8333333 } ] } ] } ... } ``` # Common suggest options: * `text` - The suggest text. The suggest text is a required option that needs to be set globally or per suggestion. # Common fuzzy suggest options * `field` - The field to fetch the candidate suggestions from. This is an required option that either needs to be set globally or per suggestion. * `analyzer` - The analyzer to analyse the suggest text with. Defaults to the search analyzer of the suggest field. * `size` - The maximum corrections to be returned per suggest text token. * `sort` - Defines how suggestions should be sorted per suggest text term. Two possible value: ** `score` - Sort by sore first, then document frequency and then the term itself. ** `frequency` - Sort by document frequency first, then simlarity score and then the term itself. * `suggest_mode` - The suggest mode controls what suggestions are included or controls for what suggest text terms, suggestions should be suggested. Three possible values can be specified: ** `missing` - Only suggest terms in the suggest text that aren't in the index. This is the default. ** `popular` - Only suggest suggestions that occur in more docs then the original suggest text term. ** `always` - Suggest any matching suggestions based on terms in the suggest text. # Other fuzzy suggest options: * `lowercase_terms` - Lower cases the suggest text terms after text analyzation. * `max_edits` - The maximum edit distance candidate suggestions can have in order to be considered as a suggestion. Can only be a value between 1 and 2. Any other value result in an bad request error being thrown. Defaults to 2. * `min_prefix` - The number of minimal prefix characters that must match in order be a candidate suggestions. Defaults to 1. Increasing this number improves spellcheck performance. Usually misspellings don't occur in the beginning of terms. * `min_query_length` - The minimum length a suggest text term must have in order to be included. Defaults to 4. * `shard_size` - Sets the maximum number of suggestions to be retrieved from each individual shard. During the reduce phase only the top N suggestions are returned based on the `size` option. Defaults to the `size` option. Setting this to a value higher than the `size` can be useful in order to get a more accurate document frequency for spelling corrections at the cost of performance. Due to the fact that terms are partitioned amongst shards, the shard level document frequencies of spelling corrections may not be precise. Increasing this will make these document frequencies more precise. * `max_inspections` - A factor that is used to multiply with the `shards_size` in order to inspect more candidate spell corrections on the shard level. Can improve accuracy at the cost of performance. Defaults to 5. * `threshold_frequency` - The minimal threshold in number of documents a suggestion should appear in. This can be specified as an absolute number or as a relative percentage of number of documents. This can improve quality by only suggesting high frequency terms. Defaults to 0f and is not enabled. If a value higher than 1 is specified then the number cannot be fractional. The shard level document frequencies are used for this option. * `max_query_frequency` - The maximum threshold in number of documents a sugges text token can exist in order to be included. Can be a relative percentage number (e.g 0.4) or an absolute number to represent document frequencies. If an value higher than 1 is specified then fractional can not be specified. Defaults to 0.01f. This can be used to exclude high frequency terms from being spellchecked. High frequency terms are usually spelled correctly on top of this this also improves the spellcheck performance. The shard level document frequencies are used for this option.
This commit is contained in:
parent
48488f707f
commit
2e68207d6d
|
@ -101,18 +101,12 @@ public class Suggest implements Iterable<Suggest.Suggestion>, Streamable, ToXCon
|
|||
/**
|
||||
* The suggestion responses corresponding with the suggestions in the request.
|
||||
*/
|
||||
public static class Suggestion implements Streamable, ToXContent {
|
||||
|
||||
static class Fields {
|
||||
|
||||
static final XContentBuilderString TERMS = new XContentBuilderString("terms");
|
||||
|
||||
}
|
||||
public static class Suggestion implements Iterable<Suggestion.Entry>, Streamable, ToXContent {
|
||||
|
||||
private String name;
|
||||
private int size;
|
||||
private Sort sort;
|
||||
private final List<Term> terms = new ArrayList<Term>(5);
|
||||
private final List<Entry> entries = new ArrayList<Entry>(5);
|
||||
|
||||
Suggestion() {
|
||||
}
|
||||
|
@ -123,16 +117,20 @@ public class Suggest implements Iterable<Suggest.Suggestion>, Streamable, ToXCon
|
|||
this.sort = sort;
|
||||
}
|
||||
|
||||
void addTerm(Term term) {
|
||||
terms.add(term);
|
||||
void addTerm(Entry entry) {
|
||||
entries.add(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entry> iterator() {
|
||||
return entries.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The terms outputted by the suggest analyzer using the suggested text. Embeds the actual suggested
|
||||
* terms.
|
||||
* @return The entries for this suggestion.
|
||||
*/
|
||||
public List<Term> getTerms() {
|
||||
return terms;
|
||||
public List<Entry> getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -144,23 +142,25 @@ public class Suggest implements Iterable<Suggest.Suggestion>, Streamable, ToXCon
|
|||
|
||||
/**
|
||||
* Merges the result of another suggestion into this suggestion.
|
||||
* For internal usage.
|
||||
*/
|
||||
public void reduce(Suggestion other) {
|
||||
assert name.equals(other.name);
|
||||
assert terms.size() == other.terms.size();
|
||||
for (int i = 0; i < terms.size(); i++) {
|
||||
Term thisTerm = terms.get(i);
|
||||
Term otherTerm = other.terms.get(i);
|
||||
thisTerm.reduce(otherTerm, sort);
|
||||
assert entries.size() == other.entries.size();
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
Entry thisEntry = entries.get(i);
|
||||
Entry otherEntry = other.entries.get(i);
|
||||
thisEntry.reduce(otherEntry, sort);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims the number of suggestions per suggest text term to the requested size.
|
||||
* Trims the number of options per suggest text term to the requested size.
|
||||
* For internal usage.
|
||||
*/
|
||||
public void trim() {
|
||||
for (Term term : terms) {
|
||||
term.trim(size);
|
||||
for (Entry entry : entries) {
|
||||
entry.trim(size);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,9 +170,9 @@ public class Suggest implements Iterable<Suggest.Suggestion>, Streamable, ToXCon
|
|||
size = in.readVInt();
|
||||
sort = Sort.fromId(in.readByte());
|
||||
int size = in.readVInt();
|
||||
terms.clear();
|
||||
entries.clear();
|
||||
for (int i = 0; i < size; i++) {
|
||||
terms.add(Term.read(in));
|
||||
entries.add(Entry.read(in));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -181,76 +181,73 @@ public class Suggest implements Iterable<Suggest.Suggestion>, Streamable, ToXCon
|
|||
out.writeString(name);
|
||||
out.writeVInt(size);
|
||||
out.writeByte(sort.id());
|
||||
out.writeVInt(terms.size());
|
||||
for (Term term : terms) {
|
||||
term.writeTo(out);
|
||||
out.writeVInt(entries.size());
|
||||
for (Entry entry : entries) {
|
||||
entry.writeTo(out);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject(name);
|
||||
builder.startArray(Fields.TERMS);
|
||||
for (Term term : terms) {
|
||||
term.toXContent(builder, params);
|
||||
builder.startArray(name);
|
||||
for (Entry entry : entries) {
|
||||
entry.toXContent(builder, params);
|
||||
}
|
||||
builder.endArray();
|
||||
builder.endObject();
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Represents a term from the suggest text, that contains the term, start/end offsets and zero or more suggested
|
||||
* terms for this term in the suggested text.
|
||||
* Represents a part from the suggest text with suggested options.
|
||||
*/
|
||||
public static class Term implements Streamable, ToXContent {
|
||||
public static class Entry implements Iterable<Entry.Option>, Streamable, ToXContent {
|
||||
|
||||
static class Fields {
|
||||
|
||||
static final XContentBuilderString TERM = new XContentBuilderString("term");
|
||||
static final XContentBuilderString SUGGESTIONS = new XContentBuilderString("suggestions");
|
||||
static final XContentBuilderString START_OFFSET = new XContentBuilderString("start_offset");
|
||||
static final XContentBuilderString END_OFFSET = new XContentBuilderString("end_offset");
|
||||
static final XContentBuilderString TEXT = new XContentBuilderString("text");
|
||||
static final XContentBuilderString OFFSET = new XContentBuilderString("offset");
|
||||
static final XContentBuilderString LENGTH = new XContentBuilderString("length");
|
||||
static final XContentBuilderString OPTIONS = new XContentBuilderString("options");
|
||||
|
||||
}
|
||||
|
||||
private Text term;
|
||||
private int startOffset;
|
||||
private int endOffset;
|
||||
private Text text;
|
||||
private int offset;
|
||||
private int length;
|
||||
|
||||
private List<SuggestedTerm> suggested;
|
||||
private List<Option> options;
|
||||
|
||||
public Term(Text term, int startOffset, int endOffset) {
|
||||
this.term = term;
|
||||
this.startOffset = startOffset;
|
||||
this.endOffset = endOffset;
|
||||
this.suggested = new ArrayList<SuggestedTerm>(5);
|
||||
Entry(Text text, int offset, int length) {
|
||||
this.text = text;
|
||||
this.offset = offset;
|
||||
this.length = length;
|
||||
this.options = new ArrayList<Option>(5);
|
||||
}
|
||||
|
||||
Term() {
|
||||
Entry() {
|
||||
}
|
||||
|
||||
void addSuggested(SuggestedTerm suggestedTerm) {
|
||||
suggested.add(suggestedTerm);
|
||||
void addOption(Option option) {
|
||||
options.add(option);
|
||||
}
|
||||
|
||||
void reduce(Term otherTerm, Sort sort) {
|
||||
assert term.equals(otherTerm.term());
|
||||
assert startOffset == otherTerm.startOffset;
|
||||
assert endOffset == otherTerm.endOffset;
|
||||
void reduce(Entry otherEntry, Sort sort) {
|
||||
assert text.equals(otherEntry.text);
|
||||
assert offset == otherEntry.offset;
|
||||
assert length == otherEntry.length;
|
||||
|
||||
for (SuggestedTerm otherSuggestedTerm : otherTerm.suggested) {
|
||||
int index = suggested.indexOf(otherSuggestedTerm);
|
||||
for (Option otherOption : otherEntry.options) {
|
||||
int index = options.indexOf(otherOption);
|
||||
if (index >= 0) {
|
||||
SuggestedTerm thisSuggestedTerm = suggested.get(index);
|
||||
thisSuggestedTerm.setFrequency(thisSuggestedTerm.frequency + otherSuggestedTerm.frequency);
|
||||
Option thisOption = options.get(index);
|
||||
thisOption.setFreq(thisOption.freq + otherOption.freq);
|
||||
} else {
|
||||
suggested.add(otherSuggestedTerm);
|
||||
options.add(otherOption);
|
||||
}
|
||||
}
|
||||
|
||||
Comparator<SuggestedTerm> comparator;
|
||||
Comparator<Option> comparator;
|
||||
switch (sort) {
|
||||
case SCORE:
|
||||
comparator = SuggestPhase.SCORE;
|
||||
|
@ -261,46 +258,48 @@ public class Suggest implements Iterable<Suggest.Suggestion>, Streamable, ToXCon
|
|||
default:
|
||||
throw new ElasticSearchException("Could not resolve comparator in reduce phase.");
|
||||
}
|
||||
Collections.sort(suggested, comparator);
|
||||
}
|
||||
|
||||
public Text term() {
|
||||
return term;
|
||||
Collections.sort(options, comparator);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the term (analyzed by suggest analyzer) originating from the suggest text.
|
||||
* @return the text (analyzed by suggest analyzer) originating from the suggest text. Usually this is a
|
||||
* single term.
|
||||
*/
|
||||
public String getTerm() {
|
||||
return term().string();
|
||||
public Text getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the start offset of this term in the suggest text.
|
||||
* @return the start offset (not analyzed) for this entry in the suggest text.
|
||||
*/
|
||||
public int getStartOffset() {
|
||||
return startOffset;
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the end offset of this term in the suggest text.
|
||||
* @return the length (not analyzed) for this entry in the suggest text.
|
||||
*/
|
||||
public int getEndOffset() {
|
||||
return endOffset;
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Option> iterator() {
|
||||
return options.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The suggested terms for this particular suggest text term. If there are no suggested terms then
|
||||
* @return The suggested options for this particular suggest entry. If there are no suggested terms then
|
||||
* an empty list is returned.
|
||||
*/
|
||||
public List<SuggestedTerm> getSuggested() {
|
||||
return suggested;
|
||||
public List<Option> getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
void trim(int size) {
|
||||
int suggestionsToRemove = Math.max(0, suggested.size() - size);
|
||||
for (int i = 0; i < suggestionsToRemove; i++) {
|
||||
suggested.remove(suggested.size() - 1);
|
||||
int optionsToRemove = Math.max(0, options.size() - size);
|
||||
for (int i = 0; i < optionsToRemove; i++) {
|
||||
options.remove(options.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -309,61 +308,61 @@ public class Suggest implements Iterable<Suggest.Suggestion>, Streamable, ToXCon
|
|||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Term term = (Term) o;
|
||||
Entry entry = (Entry) o;
|
||||
|
||||
if (endOffset != term.endOffset) return false;
|
||||
if (startOffset != term.startOffset) return false;
|
||||
if (!this.term.equals(term.term)) return false;
|
||||
if (length != entry.length) return false;
|
||||
if (offset != entry.offset) return false;
|
||||
if (!this.text.equals(entry.text)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = term.hashCode();
|
||||
result = 31 * result + startOffset;
|
||||
result = 31 * result + endOffset;
|
||||
int result = text.hashCode();
|
||||
result = 31 * result + offset;
|
||||
result = 31 * result + length;
|
||||
return result;
|
||||
}
|
||||
|
||||
static Term read(StreamInput in) throws IOException {
|
||||
Term term = new Term();
|
||||
term.readFrom(in);
|
||||
return term;
|
||||
static Entry read(StreamInput in) throws IOException {
|
||||
Entry entry = new Entry();
|
||||
entry.readFrom(in);
|
||||
return entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFrom(StreamInput in) throws IOException {
|
||||
term = in.readText();
|
||||
startOffset = in.readVInt();
|
||||
endOffset = in.readVInt();
|
||||
text = in.readText();
|
||||
offset = in.readVInt();
|
||||
length = in.readVInt();
|
||||
int suggestedWords = in.readVInt();
|
||||
suggested = new ArrayList<SuggestedTerm>(suggestedWords);
|
||||
options = new ArrayList<Option>(suggestedWords);
|
||||
for (int j = 0; j < suggestedWords; j++) {
|
||||
suggested.add(SuggestedTerm.create(in));
|
||||
options.add(Option.create(in));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeText(term);
|
||||
out.writeVInt(startOffset);
|
||||
out.writeVInt(endOffset);
|
||||
out.writeVInt(suggested.size());
|
||||
for (SuggestedTerm suggestedTerm : suggested) {
|
||||
suggestedTerm.writeTo(out);
|
||||
out.writeText(text);
|
||||
out.writeVInt(offset);
|
||||
out.writeVInt(length);
|
||||
out.writeVInt(options.size());
|
||||
for (Option option : options) {
|
||||
option.writeTo(out);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
builder.field(Fields.TERM, term);
|
||||
builder.field(Fields.START_OFFSET, startOffset);
|
||||
builder.field(Fields.END_OFFSET, endOffset);
|
||||
builder.startArray(Fields.SUGGESTIONS);
|
||||
for (SuggestedTerm suggestedTerm : suggested) {
|
||||
suggestedTerm.toXContent(builder, params);
|
||||
builder.field(Fields.TEXT, text);
|
||||
builder.field(Fields.OFFSET, offset);
|
||||
builder.field(Fields.LENGTH, length);
|
||||
builder.startArray(Fields.OPTIONS);
|
||||
for (Option option : options) {
|
||||
option.toXContent(builder, params);
|
||||
}
|
||||
builder.endArray();
|
||||
builder.endObject();
|
||||
|
@ -371,47 +370,47 @@ public class Suggest implements Iterable<Suggest.Suggestion>, Streamable, ToXCon
|
|||
}
|
||||
|
||||
/**
|
||||
* Represents the suggested term, containing a term and its document frequency and score.
|
||||
* Contains the suggested text with its document frequency and score.
|
||||
*/
|
||||
public static class SuggestedTerm implements Streamable, ToXContent {
|
||||
public static class Option implements Streamable, ToXContent {
|
||||
|
||||
static class Fields {
|
||||
|
||||
static final XContentBuilderString TERM = new XContentBuilderString("term");
|
||||
static final XContentBuilderString FREQUENCY = new XContentBuilderString("frequency");
|
||||
static final XContentBuilderString TEXT = new XContentBuilderString("text");
|
||||
static final XContentBuilderString FREQ = new XContentBuilderString("freq");
|
||||
static final XContentBuilderString SCORE = new XContentBuilderString("score");
|
||||
|
||||
}
|
||||
|
||||
private Text term;
|
||||
private int frequency;
|
||||
private Text text;
|
||||
private int freq;
|
||||
private float score;
|
||||
|
||||
SuggestedTerm(Text term, int frequency, float score) {
|
||||
this.term = term;
|
||||
this.frequency = frequency;
|
||||
Option(Text text, int freq, float score) {
|
||||
this.text = text;
|
||||
this.freq = freq;
|
||||
this.score = score;
|
||||
}
|
||||
|
||||
SuggestedTerm() {
|
||||
Option() {
|
||||
}
|
||||
|
||||
public void setFrequency(int frequency) {
|
||||
this.frequency = frequency;
|
||||
public void setFreq(int freq) {
|
||||
this.freq = freq;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The actual term.
|
||||
* @return The actual suggested text.
|
||||
*/
|
||||
public Text getTerm() {
|
||||
return term;
|
||||
public Text getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return How often this suggested term appears in the index.
|
||||
* @return How often this suggested text appears in the index.
|
||||
*/
|
||||
public int getFrequency() {
|
||||
return frequency;
|
||||
public int getFreq() {
|
||||
return freq;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -422,31 +421,31 @@ public class Suggest implements Iterable<Suggest.Suggestion>, Streamable, ToXCon
|
|||
return score;
|
||||
}
|
||||
|
||||
static SuggestedTerm create(StreamInput in) throws IOException {
|
||||
SuggestedTerm suggestion = new SuggestedTerm();
|
||||
static Option create(StreamInput in) throws IOException {
|
||||
Option suggestion = new Option();
|
||||
suggestion.readFrom(in);
|
||||
return suggestion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFrom(StreamInput in) throws IOException {
|
||||
term = in.readText();
|
||||
frequency = in.readVInt();
|
||||
text = in.readText();
|
||||
freq = in.readVInt();
|
||||
score = in.readFloat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeText(term);
|
||||
out.writeVInt(frequency);
|
||||
out.writeText(text);
|
||||
out.writeVInt(freq);
|
||||
out.writeFloat(score);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
builder.field(Fields.TERM, term);
|
||||
builder.field(Fields.FREQUENCY, frequency);
|
||||
builder.field(Fields.TEXT, text);
|
||||
builder.field(Fields.FREQ, freq);
|
||||
builder.field(Fields.SCORE, score);
|
||||
builder.endObject();
|
||||
return builder;
|
||||
|
@ -457,14 +456,14 @@ public class Suggest implements Iterable<Suggest.Suggestion>, Streamable, ToXCon
|
|||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
SuggestedTerm that = (SuggestedTerm) o;
|
||||
return term.equals(that.term);
|
||||
Option that = (Option) o;
|
||||
return text.equals(that.text);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return term.hashCode();
|
||||
return text.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -74,13 +74,9 @@ public class SuggestBuilder implements ToXContent {
|
|||
if (globalText != null) {
|
||||
builder.field("text", globalText);
|
||||
}
|
||||
|
||||
builder.startObject("suggestions");
|
||||
for (Suggestion suggestion : suggestions) {
|
||||
builder = suggestion.toXContent(builder, params);
|
||||
}
|
||||
builder.endObject();
|
||||
|
||||
builder.endObject();
|
||||
return builder;
|
||||
}
|
||||
|
@ -116,14 +112,13 @@ public class SuggestBuilder implements ToXContent {
|
|||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject(name);
|
||||
if (suggester != null) {
|
||||
builder.field("suggester", suggester);
|
||||
}
|
||||
if (text != null) {
|
||||
builder.field("text", text);
|
||||
}
|
||||
builder.startObject(suggester);
|
||||
builder = innerToXContent(builder, params);
|
||||
builder.endObject();
|
||||
builder.endObject();
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,65 +65,75 @@ public class SuggestParseElement implements SearchParseElement {
|
|||
throw new ElasticSearchIllegalArgumentException("[suggest] does not support [" + fieldName + "]");
|
||||
}
|
||||
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||
// TODO: Once we have more suggester impls we need to have different parsing logic per suggester.
|
||||
// This code is now specific for the fuzzy suggester
|
||||
if ("suggestions".equals(fieldName)) {
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
fieldName = parser.currentName();
|
||||
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||
SuggestionSearchContext.Suggestion suggestion = new SuggestionSearchContext.Suggestion();
|
||||
suggestionSearchContext.addSuggestion(fieldName, suggestion);
|
||||
String suggestionName = fieldName;
|
||||
BytesRef suggestText = null;
|
||||
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
fieldName = parser.currentName();
|
||||
} else if (token.isValue()) {
|
||||
if ("suggester".equals(fieldName)) {
|
||||
suggestion.suggester(parser.text());
|
||||
} else if ("analyzer".equals(fieldName)) {
|
||||
String analyzerName = parser.text();
|
||||
Analyzer analyzer = context.mapperService().analysisService().analyzer(analyzerName);
|
||||
if (analyzer == null) {
|
||||
throw new ElasticSearchIllegalArgumentException("Analyzer [" + analyzerName + "] doesn't exists");
|
||||
}
|
||||
suggestion.analyzer(analyzer);
|
||||
} else if ("text".equals(fieldName)) {
|
||||
suggestion.text(parser.bytes());
|
||||
} else if ("field".equals(fieldName)) {
|
||||
suggestion.setField(parser.text());
|
||||
} else if ("accuracy".equals(fieldName)) {
|
||||
suggestion.accuracy(parser.floatValue());
|
||||
} else if ("size".equals(fieldName)) {
|
||||
suggestion.size(parser.intValue());
|
||||
} else if ("suggest_mode".equals(fieldName) || "suggestMode".equals(fieldName)) {
|
||||
suggestion.suggestMode(resolveSuggestMode(parser.text()));
|
||||
} else if ("sort".equals(fieldName)) {
|
||||
suggestion.sort(resolveSort(parser.text()));
|
||||
} else if ("string_distance".equals(fieldName) || "stringDistance".equals(fieldName)) {
|
||||
suggestion.stringDistance(resolveDistance(parser.text()));
|
||||
} else if ("lowercase_terms".equals(fieldName) || "lowercaseTerms".equals(fieldName)) {
|
||||
suggestion.lowerCaseTerms(parser.booleanValue());
|
||||
} else if ("max_edits".equals(fieldName) || "maxEdits".equals(fieldName) || "fuzziness".equals(fieldName)) {
|
||||
suggestion.maxEdits(parser.intValue());
|
||||
if (suggestion.maxEdits() < 1 || suggestion.maxEdits() > LevenshteinAutomata.MAXIMUM_SUPPORTED_DISTANCE) {
|
||||
throw new ElasticSearchIllegalArgumentException("Illegal max_edits value " + suggestion.maxEdits());
|
||||
}
|
||||
} else if ("factor".equals(fieldName)) {
|
||||
suggestion.factor(parser.intValue());
|
||||
} else if ("max_term_freq".equals(fieldName) || "maxTermFreq".equals(fieldName)) {
|
||||
suggestion.maxTermFreq(parser.floatValue());
|
||||
} else if ("prefix_length".equals(fieldName) || "prefixLength".equals(fieldName)) {
|
||||
suggestion.prefixLength(parser.intValue());
|
||||
} else if ("min_word_len".equals(fieldName) || "minWordLen".equals(fieldName)) {
|
||||
suggestion.minQueryLength(parser.intValue());
|
||||
} else if ("min_doc_freq".equals(fieldName) || "minDocFreq".equals(fieldName)) {
|
||||
suggestion.minDocFreq(parser.floatValue());
|
||||
} else if ("shard_size".equals(fieldName) || "shardSize".equals(fieldName)) {
|
||||
suggestion.shardSize(parser.intValue());
|
||||
} else {
|
||||
throw new ElasticSearchIllegalArgumentException("suggester[fuzzy] doesn't support [" + fieldName + "]");
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
fieldName = parser.currentName();
|
||||
} else if (token.isValue()) {
|
||||
if ("text".equals(fieldName)) {
|
||||
suggestText = parser.bytes();
|
||||
} else {
|
||||
throw new ElasticSearchIllegalArgumentException("[suggest] does not support [" + fieldName + "]");
|
||||
}
|
||||
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||
if (suggestionName == null) {
|
||||
throw new ElasticSearchIllegalArgumentException("Suggestion must have name");
|
||||
}
|
||||
|
||||
// TODO: Once we have more suggester impls we need to have different parsing logic per suggester.
|
||||
// This code is now specific for the fuzzy suggester
|
||||
if (!"fuzzy".equals(fieldName)) {
|
||||
throw new ElasticSearchIllegalArgumentException("Suggester[" + fieldName + "] not supported");
|
||||
}
|
||||
SuggestionSearchContext.Suggestion suggestion = new SuggestionSearchContext.Suggestion();
|
||||
suggestion.text(suggestText);
|
||||
suggestionSearchContext.addSuggestion(suggestionName, suggestion);
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
fieldName = parser.currentName();
|
||||
} else if (token.isValue()) {
|
||||
if ("analyzer".equals(fieldName)) {
|
||||
String analyzerName = parser.text();
|
||||
Analyzer analyzer = context.mapperService().analysisService().analyzer(analyzerName);
|
||||
if (analyzer == null) {
|
||||
throw new ElasticSearchIllegalArgumentException("Analyzer [" + analyzerName + "] doesn't exists");
|
||||
}
|
||||
suggestion.analyzer(analyzer);
|
||||
} else if ("field".equals(fieldName)) {
|
||||
suggestion.setField(parser.text());
|
||||
} else if ("accuracy".equals(fieldName)) {
|
||||
suggestion.accuracy(parser.floatValue());
|
||||
} else if ("size".equals(fieldName)) {
|
||||
suggestion.size(parser.intValue());
|
||||
} else if ("suggest_mode".equals(fieldName) || "suggestMode".equals(fieldName)) {
|
||||
suggestion.suggestMode(resolveSuggestMode(parser.text()));
|
||||
} else if ("sort".equals(fieldName)) {
|
||||
suggestion.sort(resolveSort(parser.text()));
|
||||
} else if ("string_distance".equals(fieldName) || "stringDistance".equals(fieldName)) {
|
||||
suggestion.stringDistance(resolveDistance(parser.text()));
|
||||
} else if ("lowercase_terms".equals(fieldName) || "lowercaseTerms".equals(fieldName)) {
|
||||
suggestion.lowerCaseTerms(parser.booleanValue());
|
||||
} else if ("max_edits".equals(fieldName) || "maxEdits".equals(fieldName) || "fuzziness".equals(fieldName)) {
|
||||
suggestion.maxEdits(parser.intValue());
|
||||
if (suggestion.maxEdits() < 1 || suggestion.maxEdits() > LevenshteinAutomata.MAXIMUM_SUPPORTED_DISTANCE) {
|
||||
throw new ElasticSearchIllegalArgumentException("Illegal max_edits value " + suggestion.maxEdits());
|
||||
}
|
||||
} else if ("factor".equals(fieldName)) {
|
||||
suggestion.factor(parser.intValue());
|
||||
} else if ("max_term_freq".equals(fieldName) || "maxTermFreq".equals(fieldName)) {
|
||||
suggestion.maxTermFreq(parser.floatValue());
|
||||
} else if ("prefix_length".equals(fieldName) || "prefixLength".equals(fieldName)) {
|
||||
suggestion.prefixLength(parser.intValue());
|
||||
} else if ("min_word_len".equals(fieldName) || "minWordLen".equals(fieldName)) {
|
||||
suggestion.minQueryLength(parser.intValue());
|
||||
} else if ("min_doc_freq".equals(fieldName) || "minDocFreq".equals(fieldName)) {
|
||||
suggestion.minDocFreq(parser.floatValue());
|
||||
} else if ("shard_size".equals(fieldName) || "shardSize".equals(fieldName)) {
|
||||
suggestion.shardSize(parser.intValue());
|
||||
} else {
|
||||
throw new ElasticSearchIllegalArgumentException("suggester[fuzzy] doesn't support [" + fieldName + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -134,9 +144,6 @@ public class SuggestParseElement implements SearchParseElement {
|
|||
|
||||
// Verify options and set defaults
|
||||
for (SuggestionSearchContext.Suggestion command : suggestionSearchContext.suggestions().values()) {
|
||||
if (command.suggester() == null) {
|
||||
throw new ElasticSearchIllegalArgumentException("The required suggester option is missing");
|
||||
}
|
||||
if (command.field() == null) {
|
||||
throw new ElasticSearchIllegalArgumentException("The required field option is missing");
|
||||
}
|
||||
|
|
|
@ -86,11 +86,7 @@ public class SuggestPhase extends AbstractComponent implements SearchPhase {
|
|||
List<Suggestion> suggestions = new ArrayList<Suggestion>(2);
|
||||
for (Map.Entry<String, SuggestionSearchContext.Suggestion> entry : suggest.suggestions().entrySet()) {
|
||||
SuggestionSearchContext.Suggestion suggestion = entry.getValue();
|
||||
if ("fuzzy".equals(suggestion.suggester())) {
|
||||
suggestions.add(executeDirectSpellChecker(entry.getKey(), suggestion, context, spare));
|
||||
} else {
|
||||
throw new ElasticSearchIllegalArgumentException("Unsupported suggester[" + suggestion.suggester() + "]");
|
||||
}
|
||||
suggestions.add(executeDirectSpellChecker(entry.getKey(), suggestion, context, spare));
|
||||
}
|
||||
context.queryResult().suggest(new Suggest(suggestions));
|
||||
} catch (IOException e) {
|
||||
|
@ -133,12 +129,12 @@ public class SuggestPhase extends AbstractComponent implements SearchPhase {
|
|||
token.term, suggestion.shardSize(), indexReader, suggestion.suggestMode()
|
||||
);
|
||||
Text key = new BytesText(new BytesArray(token.term.bytes()));
|
||||
Suggestion.Term resultTerm = new Suggestion.Term(key, token.startOffset, token.endOffset);
|
||||
Suggestion.Entry resultEntry = new Suggestion.Entry(key, token.startOffset, token.endOffset - token.startOffset);
|
||||
for (SuggestWord suggestWord : suggestedWords) {
|
||||
Text word = new StringText(suggestWord.string);
|
||||
resultTerm.addSuggested(new Suggestion.Term.SuggestedTerm(word, suggestWord.freq, suggestWord.score));
|
||||
resultEntry.addOption(new Suggestion.Entry.Option(word, suggestWord.freq, suggestWord.score));
|
||||
}
|
||||
response.addTerm(resultTerm);
|
||||
response.addTerm(resultEntry);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
@ -164,15 +160,15 @@ public class SuggestPhase extends AbstractComponent implements SearchPhase {
|
|||
}
|
||||
|
||||
private static Comparator<SuggestWord> LUCENE_FREQUENCY = new SuggestWordFrequencyComparator();
|
||||
public static Comparator<Suggestion.Term.SuggestedTerm> SCORE = new Score();
|
||||
public static Comparator<Suggestion.Term.SuggestedTerm> FREQUENCY = new Frequency();
|
||||
public static Comparator<Suggestion.Entry.Option> SCORE = new Score();
|
||||
public static Comparator<Suggestion.Entry.Option> FREQUENCY = new Frequency();
|
||||
|
||||
// Same behaviour as comparators in suggest module, but for SuggestedWord
|
||||
// Highest score first, then highest freq first, then lowest term first
|
||||
public static class Score implements Comparator<Suggestion.Term.SuggestedTerm> {
|
||||
public static class Score implements Comparator<Suggestion.Entry.Option> {
|
||||
|
||||
@Override
|
||||
public int compare(Suggestion.Term.SuggestedTerm first, Suggestion.Term.SuggestedTerm second) {
|
||||
public int compare(Suggestion.Entry.Option first, Suggestion.Entry.Option second) {
|
||||
// first criteria: the distance
|
||||
int cmp = Float.compare(second.getScore(), first.getScore());
|
||||
if (cmp != 0) {
|
||||
|
@ -180,24 +176,24 @@ public class SuggestPhase extends AbstractComponent implements SearchPhase {
|
|||
}
|
||||
|
||||
// second criteria (if first criteria is equal): the popularity
|
||||
cmp = second.getFrequency() - first.getFrequency();
|
||||
cmp = second.getFreq() - first.getFreq();
|
||||
if (cmp != 0) {
|
||||
return cmp;
|
||||
}
|
||||
// third criteria: term text
|
||||
return first.getTerm().compareTo(second.getTerm());
|
||||
return first.getText().compareTo(second.getText());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Same behaviour as comparators in suggest module, but for SuggestedWord
|
||||
// Highest freq first, then highest score first, then lowest term first
|
||||
public static class Frequency implements Comparator<Suggestion.Term.SuggestedTerm> {
|
||||
public static class Frequency implements Comparator<Suggestion.Entry.Option> {
|
||||
|
||||
@Override
|
||||
public int compare(Suggestion.Term.SuggestedTerm first, Suggestion.Term.SuggestedTerm second) {
|
||||
public int compare(Suggestion.Entry.Option first, Suggestion.Entry.Option second) {
|
||||
// first criteria: the popularity
|
||||
int cmp = second.getFrequency() - first.getFrequency();
|
||||
int cmp = second.getFreq() - first.getFreq();
|
||||
if (cmp != 0) {
|
||||
return cmp;
|
||||
}
|
||||
|
@ -209,7 +205,7 @@ public class SuggestPhase extends AbstractComponent implements SearchPhase {
|
|||
}
|
||||
|
||||
// third criteria: term text
|
||||
return first.getTerm().compareTo(second.getTerm());
|
||||
return first.getText().compareTo(second.getText());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -44,7 +44,6 @@ public class SuggestionSearchContext {
|
|||
|
||||
public static class Suggestion {
|
||||
|
||||
private String suggester;
|
||||
private BytesRef text;
|
||||
private String field;
|
||||
private Analyzer analyzer;
|
||||
|
@ -62,14 +61,6 @@ public class SuggestionSearchContext {
|
|||
private Float minDocFreq;
|
||||
private Integer shardSize;
|
||||
|
||||
public String suggester() {
|
||||
return suggester;
|
||||
}
|
||||
|
||||
public void suggester(String suggester) {
|
||||
this.suggester = suggester;
|
||||
}
|
||||
|
||||
public BytesRef text() {
|
||||
return text;
|
||||
}
|
||||
|
|
|
@ -142,8 +142,8 @@ public class SuggestSearchBenchMark {
|
|||
System.err.println("No suggestions");
|
||||
continue;
|
||||
}
|
||||
List<Suggest.Suggestion.Term.SuggestedTerm> suggestedTerms = response.suggest().getSuggestions().get(0).getTerms().get(0).getSuggested();
|
||||
if (suggestedTerms == null || suggestedTerms.isEmpty()) {
|
||||
List<Suggest.Suggestion.Entry.Option> options = response.suggest().getSuggestions().get(0).getEntries().get(0).getOptions();
|
||||
if (options == null || options.isEmpty()) {
|
||||
System.err.println("No suggestions");
|
||||
}
|
||||
startChar++;
|
||||
|
|
|
@ -107,12 +107,12 @@ public class SuggestSearchTests extends AbstractNodesTests {
|
|||
assertThat(search.suggest(), notNullValue());
|
||||
assertThat(search.suggest().getSuggestions().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getName(), equalTo("test"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getTerms().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getTerms().get(0).getTerm(), equalTo("abcd"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getTerms().get(0).getSuggested().size(), equalTo(3));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getTerms().get(0).getSuggested().get(0).getTerm().string(), equalTo("aacd"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getTerms().get(0).getSuggested().get(1).getTerm().string(), equalTo("abbd"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getTerms().get(0).getSuggested().get(2).getTerm().string(), equalTo("abcc"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getEntries().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getEntries().get(0).getText().string(), equalTo("abcd"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getEntries().get(0).getOptions().size(), equalTo(3));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getEntries().get(0).getOptions().get(0).getText().string(), equalTo("aacd"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getEntries().get(0).getOptions().get(1).getText().string(), equalTo("abbd"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getEntries().get(0).getOptions().get(2).getText().string(), equalTo("abcc"));
|
||||
|
||||
client.prepareSearch()
|
||||
.addSuggestion(
|
||||
|
@ -125,11 +125,11 @@ public class SuggestSearchTests extends AbstractNodesTests {
|
|||
assertThat(search.suggest(), notNullValue());
|
||||
assertThat(search.suggest().getSuggestions().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getName(), equalTo("test"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getTerms().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getTerms().get(0).getSuggested().size(), equalTo(3));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getTerms().get(0).getSuggested().get(0).getTerm().string(), equalTo("aacd"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getTerms().get(0).getSuggested().get(1).getTerm().string(), equalTo("abbd"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getTerms().get(0).getSuggested().get(2).getTerm().string(), equalTo("abcc"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getEntries().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getEntries().get(0).getOptions().size(), equalTo(3));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getEntries().get(0).getOptions().get(0).getText().string(), equalTo("aacd"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getEntries().get(0).getOptions().get(1).getText().string(), equalTo("abbd"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getEntries().get(0).getOptions().get(2).getText().string(), equalTo("abcc"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -150,9 +150,9 @@ public class SuggestSearchTests extends AbstractNodesTests {
|
|||
assertThat(search.suggest(), notNullValue());
|
||||
assertThat(search.suggest().getSuggestions().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getName(), equalTo("test"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getTerms().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getTerms().get(0).getTerm(), equalTo("abcd"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getTerms().get(0).getSuggested().size(), equalTo(0));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getEntries().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getEntries().get(0).getText().string(), equalTo("abcd"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getEntries().get(0).getOptions().size(), equalTo(0));
|
||||
|
||||
client.prepareSearch()
|
||||
.addSuggestion(
|
||||
|
@ -165,8 +165,8 @@ public class SuggestSearchTests extends AbstractNodesTests {
|
|||
assertThat(search.suggest(), notNullValue());
|
||||
assertThat(search.suggest().getSuggestions().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getName(), equalTo("test"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getTerms().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getTerms().get(0).getSuggested().size(), equalTo(0));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getEntries().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getEntries().get(0).getOptions().size(), equalTo(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -224,18 +224,24 @@ public class SuggestSearchTests extends AbstractNodesTests {
|
|||
assertThat(search.suggest(), notNullValue());
|
||||
assertThat(search.suggest().getSuggestions().size(), equalTo(3));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getName(), equalTo("size1"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getTerms().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getTerms().get(0).getSuggested().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getTerms().get(0).getSuggested().get(0).getTerm().string(), equalTo("prefix_aacd"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getEntries().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getEntries().get(0).getOptions().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getEntries().get(0).getOptions().get(0).getText().string(), equalTo("prefix_aacd"));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getName(), equalTo("field2"));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getTerms().size(), equalTo(2));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getTerms().get(0).getSuggested().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getTerms().get(1).getSuggested().size(), equalTo(3));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getTerms().get(1).getSuggested().get(0).getTerm().string(), equalTo("prefix_eeeh"));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getTerms().get(1).getSuggested().get(1).getTerm().string(), equalTo("prefix_efff"));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getTerms().get(1).getSuggested().get(2).getTerm().string(), equalTo("prefix_eggg"));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getEntries().size(), equalTo(2));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getEntries().get(0).getText().string(), equalTo("prefix_eeeh"));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getEntries().get(0).getOffset(), equalTo(0));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getEntries().get(0).getLength(), equalTo(11));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getEntries().get(0).getOptions().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getEntries().get(1).getText().string(), equalTo("prefix_efgh"));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getEntries().get(1).getOffset(), equalTo(12));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getEntries().get(1).getLength(), equalTo(11));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getEntries().get(1).getOptions().size(), equalTo(3));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getEntries().get(1).getOptions().get(0).getText().string(), equalTo("prefix_eeeh"));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getEntries().get(1).getOptions().get(1).getText().string(), equalTo("prefix_efff"));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getEntries().get(1).getOptions().get(2).getText().string(), equalTo("prefix_eggg"));
|
||||
assertThat(search.suggest().getSuggestions().get(2).getName(), equalTo("accuracy"));
|
||||
assertThat(search.suggest().getSuggestions().get(2).getTerms().get(0).getSuggested().isEmpty(), equalTo(true));
|
||||
assertThat(search.suggest().getSuggestions().get(2).getEntries().get(0).getOptions().isEmpty(), equalTo(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -289,42 +295,42 @@ public class SuggestSearchTests extends AbstractNodesTests {
|
|||
assertThat(search.suggest(), notNullValue());
|
||||
assertThat(search.suggest().getSuggestions().size(), equalTo(4));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getName(), equalTo("size3SortScoreFirst"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getTerms().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getTerms().get(0).getSuggested().size(), equalTo(3));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getTerms().get(0).getSuggested().get(0).getTerm().string(), equalTo("prefix_aacd"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getTerms().get(0).getSuggested().get(1).getTerm().string(), equalTo("prefix_abcc"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getTerms().get(0).getSuggested().get(2).getTerm().string(), equalTo("prefix_accd"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getEntries().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getEntries().get(0).getOptions().size(), equalTo(3));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getEntries().get(0).getOptions().get(0).getText().string(), equalTo("prefix_aacd"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getEntries().get(0).getOptions().get(1).getText().string(), equalTo("prefix_abcc"));
|
||||
assertThat(search.suggest().getSuggestions().get(0).getEntries().get(0).getOptions().get(2).getText().string(), equalTo("prefix_accd"));
|
||||
|
||||
assertThat(search.suggest().getSuggestions().get(1).getName(), equalTo("size10SortScoreFirst"));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getTerms().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getTerms().get(0).getSuggested().size(), equalTo(10));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getTerms().get(0).getSuggested().get(0).getTerm().string(), equalTo("prefix_aacd"));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getTerms().get(0).getSuggested().get(1).getTerm().string(), equalTo("prefix_abcc"));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getTerms().get(0).getSuggested().get(2).getTerm().string(), equalTo("prefix_accd"));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getEntries().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getEntries().get(0).getOptions().size(), equalTo(10));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getEntries().get(0).getOptions().get(0).getText().string(), equalTo("prefix_aacd"));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getEntries().get(0).getOptions().get(1).getText().string(), equalTo("prefix_abcc"));
|
||||
assertThat(search.suggest().getSuggestions().get(1).getEntries().get(0).getOptions().get(2).getText().string(), equalTo("prefix_accd"));
|
||||
// This fails sometimes. Depending on how the docs are sharded. The suggested suggest corrections get the df on shard level, which
|
||||
// isn't correct comparing it to the index level.
|
||||
// assertThat(search.suggest().suggestions().get(1).getSuggestedWords().get("prefix_abcd").get(3).getTerm(), equalTo("prefix_aaad"));
|
||||
|
||||
assertThat(search.suggest().getSuggestions().get(2).getName(), equalTo("size3SortScoreFirstMaxEdits1"));
|
||||
assertThat(search.suggest().getSuggestions().get(2).getTerms().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(2).getTerms().get(0).getSuggested().size(), equalTo(3));
|
||||
assertThat(search.suggest().getSuggestions().get(2).getTerms().get(0).getSuggested().get(0).getTerm().string(), equalTo("prefix_aacd"));
|
||||
assertThat(search.suggest().getSuggestions().get(2).getTerms().get(0).getSuggested().get(1).getTerm().string(), equalTo("prefix_abcc"));
|
||||
assertThat(search.suggest().getSuggestions().get(2).getTerms().get(0).getSuggested().get(2).getTerm().string(), equalTo("prefix_accd"));
|
||||
assertThat(search.suggest().getSuggestions().get(2).getEntries().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(2).getEntries().get(0).getOptions().size(), equalTo(3));
|
||||
assertThat(search.suggest().getSuggestions().get(2).getEntries().get(0).getOptions().get(0).getText().string(), equalTo("prefix_aacd"));
|
||||
assertThat(search.suggest().getSuggestions().get(2).getEntries().get(0).getOptions().get(1).getText().string(), equalTo("prefix_abcc"));
|
||||
assertThat(search.suggest().getSuggestions().get(2).getEntries().get(0).getOptions().get(2).getText().string(), equalTo("prefix_accd"));
|
||||
|
||||
assertThat(search.suggest().getSuggestions().get(3).getName(), equalTo("size10SortFrequencyFirst"));
|
||||
assertThat(search.suggest().getSuggestions().get(3).getTerms().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(3).getTerms().get(0).getSuggested().size(), equalTo(10));
|
||||
assertThat(search.suggest().getSuggestions().get(3).getTerms().get(0).getSuggested().get(0).getTerm().string(), equalTo("prefix_aaad"));
|
||||
assertThat(search.suggest().getSuggestions().get(3).getTerms().get(0).getSuggested().get(1).getTerm().string(), equalTo("prefix_abbb"));
|
||||
assertThat(search.suggest().getSuggestions().get(3).getTerms().get(0).getSuggested().get(2).getTerm().string(), equalTo("prefix_aaca"));
|
||||
assertThat(search.suggest().getSuggestions().get(3).getTerms().get(0).getSuggested().get(3).getTerm().string(), equalTo("prefix_abba"));
|
||||
assertThat(search.suggest().getSuggestions().get(3).getTerms().get(0).getSuggested().get(4).getTerm().string(), equalTo("prefix_accc"));
|
||||
assertThat(search.suggest().getSuggestions().get(3).getTerms().get(0).getSuggested().get(5).getTerm().string(), equalTo("prefix_addd"));
|
||||
assertThat(search.suggest().getSuggestions().get(3).getTerms().get(0).getSuggested().get(6).getTerm().string(), equalTo("prefix_abaa"));
|
||||
assertThat(search.suggest().getSuggestions().get(3).getTerms().get(0).getSuggested().get(7).getTerm().string(), equalTo("prefix_dbca"));
|
||||
assertThat(search.suggest().getSuggestions().get(3).getTerms().get(0).getSuggested().get(8).getTerm().string(), equalTo("prefix_cbad"));
|
||||
assertThat(search.suggest().getSuggestions().get(3).getTerms().get(0).getSuggested().get(9).getTerm().string(), equalTo("prefix_aacd"));
|
||||
assertThat(search.suggest().getSuggestions().get(3).getEntries().size(), equalTo(1));
|
||||
assertThat(search.suggest().getSuggestions().get(3).getEntries().get(0).getOptions().size(), equalTo(10));
|
||||
assertThat(search.suggest().getSuggestions().get(3).getEntries().get(0).getOptions().get(0).getText().string(), equalTo("prefix_aaad"));
|
||||
assertThat(search.suggest().getSuggestions().get(3).getEntries().get(0).getOptions().get(1).getText().string(), equalTo("prefix_abbb"));
|
||||
assertThat(search.suggest().getSuggestions().get(3).getEntries().get(0).getOptions().get(2).getText().string(), equalTo("prefix_aaca"));
|
||||
assertThat(search.suggest().getSuggestions().get(3).getEntries().get(0).getOptions().get(3).getText().string(), equalTo("prefix_abba"));
|
||||
assertThat(search.suggest().getSuggestions().get(3).getEntries().get(0).getOptions().get(4).getText().string(), equalTo("prefix_accc"));
|
||||
assertThat(search.suggest().getSuggestions().get(3).getEntries().get(0).getOptions().get(5).getText().string(), equalTo("prefix_addd"));
|
||||
assertThat(search.suggest().getSuggestions().get(3).getEntries().get(0).getOptions().get(6).getText().string(), equalTo("prefix_abaa"));
|
||||
assertThat(search.suggest().getSuggestions().get(3).getEntries().get(0).getOptions().get(7).getText().string(), equalTo("prefix_dbca"));
|
||||
assertThat(search.suggest().getSuggestions().get(3).getEntries().get(0).getOptions().get(8).getText().string(), equalTo("prefix_cbad"));
|
||||
assertThat(search.suggest().getSuggestions().get(3).getEntries().get(0).getOptions().get(9).getText().string(), equalTo("prefix_aacd"));
|
||||
// assertThat(search.suggest().suggestions().get(3).getSuggestedWords().get("prefix_abcd").get(4).getTerm(), equalTo("prefix_abcc"));
|
||||
// assertThat(search.suggest().suggestions().get(3).getSuggestedWords().get("prefix_abcd").get(4).getTerm(), equalTo("prefix_accd"));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue