/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF 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.apache.lucene.search.suggest;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Comparator;
import java.util.List;
import java.util.Set;

import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.spell.Dictionary;
import org.apache.lucene.store.DataInput;
import org.apache.lucene.store.DataOutput;
import org.apache.lucene.store.InputStreamDataInput;
import org.apache.lucene.store.OutputStreamDataOutput;
import org.apache.lucene.util.Accountable;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.PriorityQueue;

Simple Lookup interface for CharSequence suggestions.
@lucene.experimental
/** * Simple Lookup interface for {@link CharSequence} suggestions. * @lucene.experimental */
public abstract class Lookup implements Accountable {
Result of a lookup.
@lucene.experimental
/** * Result of a lookup. * @lucene.experimental */
public static final class LookupResult implements Comparable<LookupResult> {
the key's text
/** the key's text */
public final CharSequence key;
Expert: custom Object to hold the result of a highlighted suggestion.
/** Expert: custom Object to hold the result of a * highlighted suggestion. */
public final Object highlightKey;
the key's weight
/** the key's weight */
public final long value;
the key's payload (null if not present)
/** the key's payload (null if not present) */
public final BytesRef payload;
the key's contexts (null if not present)
/** the key's contexts (null if not present) */
public final Set<BytesRef> contexts;
Create a new result from a key+weight pair.
/** * Create a new result from a key+weight pair. */
public LookupResult(CharSequence key, long value) { this(key, null, value, null, null); }
Create a new result from a key+weight+payload triple.
/** * Create a new result from a key+weight+payload triple. */
public LookupResult(CharSequence key, long value, BytesRef payload) { this(key, null, value, payload, null); }
Create a new result from a key+highlightKey+weight+payload triple.
/** * Create a new result from a key+highlightKey+weight+payload triple. */
public LookupResult(CharSequence key, Object highlightKey, long value, BytesRef payload) { this(key, highlightKey, value, payload, null); }
Create a new result from a key+weight+payload+contexts triple.
/** * Create a new result from a key+weight+payload+contexts triple. */
public LookupResult(CharSequence key, long value, BytesRef payload, Set<BytesRef> contexts) { this(key, null, value, payload, contexts); }
Create a new result from a key+weight+contexts triple.
/** * Create a new result from a key+weight+contexts triple. */
public LookupResult(CharSequence key, long value, Set<BytesRef> contexts) { this(key, null, value, null, contexts); }
Create a new result from a key+highlightKey+weight+payload+contexts triple.
/** * Create a new result from a key+highlightKey+weight+payload+contexts triple. */
public LookupResult(CharSequence key, Object highlightKey, long value, BytesRef payload, Set<BytesRef> contexts) { this.key = key; this.highlightKey = highlightKey; this.value = value; this.payload = payload; this.contexts = contexts; } @Override public String toString() { return key + "/" + value; }
Compare alphabetically.
/** Compare alphabetically. */
@Override public int compareTo(LookupResult o) { return CHARSEQUENCE_COMPARATOR.compare(key, o.key); } }
A simple char-by-char comparator for CharSequence
/** * A simple char-by-char comparator for {@link CharSequence} */
public static final Comparator<CharSequence> CHARSEQUENCE_COMPARATOR = new CharSequenceComparator(); private static class CharSequenceComparator implements Comparator<CharSequence> { @Override public int compare(CharSequence o1, CharSequence o2) { final int l1 = o1.length(); final int l2 = o2.length(); final int aStop = Math.min(l1, l2); for (int i = 0; i < aStop; i++) { int diff = o1.charAt(i) - o2.charAt(i); if (diff != 0) { return diff; } } // One is a prefix of the other, or, they are equal: return l1 - l2; } }
A PriorityQueue collecting a fixed size of high priority LookupResult
/** * A {@link PriorityQueue} collecting a fixed size of high priority {@link LookupResult} */
public static final class LookupPriorityQueue extends PriorityQueue<LookupResult> { // TODO: should we move this out of the interface into a utility class?
Creates a new priority queue of the specified size.
/** * Creates a new priority queue of the specified size. */
public LookupPriorityQueue(int size) { super(size); } @Override protected boolean lessThan(LookupResult a, LookupResult b) { return a.value < b.value; }
Returns the top N results in descending order.
Returns:the top N results in descending order.
/** * Returns the top N results in descending order. * @return the top N results in descending order. */
public LookupResult[] getResults() { int size = size(); LookupResult[] res = new LookupResult[size]; for (int i = size - 1; i >= 0; i--) { res[i] = pop(); } return res; } }
Sole constructor. (For invocation by subclass constructors, typically implicit.)
/** * Sole constructor. (For invocation by subclass * constructors, typically implicit.) */
public Lookup() {}
Build lookup from a dictionary. Some implementations may require sorted or unsorted keys from the dictionary's iterator - use SortedInputIterator or UnsortedInputIterator in such case.
/** Build lookup from a dictionary. Some implementations may require sorted * or unsorted keys from the dictionary's iterator - use * {@link SortedInputIterator} or * {@link UnsortedInputIterator} in such case. */
public void build(Dictionary dict) throws IOException { build(dict.getEntryIterator()); }
Calls load(DataInput) after converting InputStream to DataInput
/** * Calls {@link #load(DataInput)} after converting * {@link InputStream} to {@link DataInput} */
public boolean load(InputStream input) throws IOException { DataInput dataIn = new InputStreamDataInput(input); try { return load(dataIn); } finally { IOUtils.close(input); } }
Calls store(DataOutput) after converting OutputStream to DataOutput
/** * Calls {@link #store(DataOutput)} after converting * {@link OutputStream} to {@link DataOutput} */
public boolean store(OutputStream output) throws IOException { DataOutput dataOut = new OutputStreamDataOutput(output); try { return store(dataOut); } finally { IOUtils.close(output); } }
Get the number of entries the lookup was built with
Returns:total number of suggester entries
/** * Get the number of entries the lookup was built with * @return total number of suggester entries */
public abstract long getCount() throws IOException;
Builds up a new internal Lookup representation based on the given InputIterator. The implementation might re-sort the data internally.
/** * Builds up a new internal {@link Lookup} representation based on the given {@link InputIterator}. * The implementation might re-sort the data internally. */
public abstract void build(InputIterator inputIterator) throws IOException;
Look up a key and return possible completion for this key.
Params:
  • key – lookup key. Depending on the implementation this may be a prefix, misspelling, or even infix.
  • onlyMorePopular – return only more popular results
  • num – maximum number of results to return
Returns:a list of possible completions, with their relative weight (e.g. popularity)
/** * Look up a key and return possible completion for this key. * @param key lookup key. Depending on the implementation this may be * a prefix, misspelling, or even infix. * @param onlyMorePopular return only more popular results * @param num maximum number of results to return * @return a list of possible completions, with their relative weight (e.g. popularity) */
public List<LookupResult> lookup(CharSequence key, boolean onlyMorePopular, int num) throws IOException { return lookup(key, null, onlyMorePopular, num); }
Look up a key and return possible completion for this key.
Params:
  • key – lookup key. Depending on the implementation this may be a prefix, misspelling, or even infix.
  • contexts – contexts to filter the lookup by, or null if all contexts are allowed; if the suggestion contains any of the contexts, it's a match
  • onlyMorePopular – return only more popular results
  • num – maximum number of results to return
Returns:a list of possible completions, with their relative weight (e.g. popularity)
/** * Look up a key and return possible completion for this key. * @param key lookup key. Depending on the implementation this may be * a prefix, misspelling, or even infix. * @param contexts contexts to filter the lookup by, or null if all contexts are allowed; if the suggestion contains any of the contexts, it's a match * @param onlyMorePopular return only more popular results * @param num maximum number of results to return * @return a list of possible completions, with their relative weight (e.g. popularity) */
public abstract List<LookupResult> lookup(CharSequence key, Set<BytesRef> contexts, boolean onlyMorePopular, int num) throws IOException;
Look up a key and return possible completion for this key. This needs to be overridden by all implementing classes as the default implementation just returns null
Params:
  • key – the lookup key
  • contextFilerQuery – A query for further filtering the result of the key lookup
  • num – maximum number of results to return
  • allTermsRequired – true is all terms are required
  • doHighlight – set to true if key should be highlighted
Throws:
Returns:a list of suggestions/completions. The default implementation returns null, meaning each @Lookup implementation should override this and provide their own implementation
/** * Look up a key and return possible completion for this key. * This needs to be overridden by all implementing classes as the default implementation just returns null * * @param key the lookup key * @param contextFilerQuery A query for further filtering the result of the key lookup * @param num maximum number of results to return * @param allTermsRequired true is all terms are required * @param doHighlight set to true if key should be highlighted * @return a list of suggestions/completions. The default implementation returns null, meaning each @Lookup implementation should override this and provide their own implementation * @throws IOException when IO exception occurs */
public List<LookupResult> lookup(CharSequence key, BooleanQuery contextFilerQuery, int num, boolean allTermsRequired, boolean doHighlight) throws IOException{ return null; }
Persist the constructed lookup data to a directory. Optional operation.
Params:
Throws:
Returns:true if successful, false if unsuccessful or not supported.
/** * Persist the constructed lookup data to a directory. Optional operation. * @param output {@link DataOutput} to write the data to. * @return true if successful, false if unsuccessful or not supported. * @throws IOException when fatal IO error occurs. */
public abstract boolean store(DataOutput output) throws IOException;
Discard current lookup data and load it from a previously saved copy. Optional operation.
Params:
  • input – the DataInput to load the lookup data.
Throws:
Returns:true if completed successfully, false if unsuccessful or not supported.
/** * Discard current lookup data and load it from a previously saved copy. * Optional operation. * @param input the {@link DataInput} to load the lookup data. * @return true if completed successfully, false if unsuccessful or not supported. * @throws IOException when fatal IO error occurs. */
public abstract boolean load(DataInput input) throws IOException; }