如何在 vespa 中进行预输入搜索?
How typeahead search should be done in vespa?
我正在尝试使用 vespa 构建预输入搜索。由于数据量大,不想用streaming模式。通配符搜索是我期待看到的东西,但它看起来仅限于流模式(正则表达式和 match:substring 仅适用于流模式)。任何关于如何实现它或定制的指示将不胜感激。
我看到应用程序为此做的如下:
将所有文本放入一个属性数组中,并在该数组上设置快速搜索。这为您提供了一致的非常低的延迟,因为您只访问内存,并且能够使用前缀匹配。它会禁用全文相关性,但您不需要它。
使用前缀匹配,而不是子字符串。如果你想通过前缀匹配所有术语,你可以在搜索定义的字段上设置 match: prefix 。不过,只对最后一个词进行前缀匹配可能会提供更好的用户体验。在这种情况下,保持默认匹配并重写查询(在搜索器中)以创建最后一个 WordItem 和 PrefixItem。
例如,您可以像这样在搜索定义中定义字段:
field suggestions type array<string> {
indexing: input myinputtextfield |split "\s+" | summary | attribute
attribute: fast-search
}
要对最后一个词进行前缀匹配,请添加一个 Searcher component,它会执行如下操作:
import com.yahoo.prelude.query.CompositeItem;
import com.yahoo.prelude.query.Item;
import com.yahoo.prelude.query.PrefixItem;
import com.yahoo.prelude.query.WordItem;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
import com.yahoo.search.Searcher;
import com.yahoo.search.query.QueryTree;
import com.yahoo.search.searchchain.Execution;
import java.util.ListIterator;
public class PrefixMatchSearcher extends Searcher {
@Override
public Result search(Query query, Execution execution) {
matchLastByPrefix(query);
return execution.search(query);
}
private boolean matchLastByPrefix(Query query) {
boolean spaceTerminated = query.getModel().getQueryString().endsWith(" ");
if (spaceTerminated) return false;
QueryTree tree = query.getModel().getQueryTree();
if (tree.getRoot() instanceof WordItem) {
tree.setRoot(toPrefixItem((WordItem) tree.getRoot()));
return true;
}
else if (tree.getRoot() instanceof CompositeItem) {
CompositeItem root = (CompositeItem) tree.getRoot();
for (ListIterator<Item> i = root.getItemIterator(); i.hasNext();) {
Item child = i.next();
if (i.hasNext()) continue; // Skip to last
if (child instanceof WordItem) {
i.set(toPrefixItem((WordItem)child));
return true;
}
}
}
return false;
}
private PrefixItem toPrefixItem(WordItem word) {
return new PrefixItem(word.getWord(), word.getIndexName());
}
}
我正在尝试使用 vespa 构建预输入搜索。由于数据量大,不想用streaming模式。通配符搜索是我期待看到的东西,但它看起来仅限于流模式(正则表达式和 match:substring 仅适用于流模式)。任何关于如何实现它或定制的指示将不胜感激。
我看到应用程序为此做的如下:
将所有文本放入一个属性数组中,并在该数组上设置快速搜索。这为您提供了一致的非常低的延迟,因为您只访问内存,并且能够使用前缀匹配。它会禁用全文相关性,但您不需要它。
使用前缀匹配,而不是子字符串。如果你想通过前缀匹配所有术语,你可以在搜索定义的字段上设置 match: prefix 。不过,只对最后一个词进行前缀匹配可能会提供更好的用户体验。在这种情况下,保持默认匹配并重写查询(在搜索器中)以创建最后一个 WordItem 和 PrefixItem。
例如,您可以像这样在搜索定义中定义字段:
field suggestions type array<string> {
indexing: input myinputtextfield |split "\s+" | summary | attribute
attribute: fast-search
}
要对最后一个词进行前缀匹配,请添加一个 Searcher component,它会执行如下操作:
import com.yahoo.prelude.query.CompositeItem;
import com.yahoo.prelude.query.Item;
import com.yahoo.prelude.query.PrefixItem;
import com.yahoo.prelude.query.WordItem;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
import com.yahoo.search.Searcher;
import com.yahoo.search.query.QueryTree;
import com.yahoo.search.searchchain.Execution;
import java.util.ListIterator;
public class PrefixMatchSearcher extends Searcher {
@Override
public Result search(Query query, Execution execution) {
matchLastByPrefix(query);
return execution.search(query);
}
private boolean matchLastByPrefix(Query query) {
boolean spaceTerminated = query.getModel().getQueryString().endsWith(" ");
if (spaceTerminated) return false;
QueryTree tree = query.getModel().getQueryTree();
if (tree.getRoot() instanceof WordItem) {
tree.setRoot(toPrefixItem((WordItem) tree.getRoot()));
return true;
}
else if (tree.getRoot() instanceof CompositeItem) {
CompositeItem root = (CompositeItem) tree.getRoot();
for (ListIterator<Item> i = root.getItemIterator(); i.hasNext();) {
Item child = i.next();
if (i.hasNext()) continue; // Skip to last
if (child instanceof WordItem) {
i.set(toPrefixItem((WordItem)child));
return true;
}
}
}
return false;
}
private PrefixItem toPrefixItem(WordItem word) {
return new PrefixItem(word.getWord(), word.getIndexName());
}
}