10

在 Lucene 查询语法中,我想将 * 和 ~ 组合在一个有效的查询中,类似于:bla~* //invalid query

含义:请匹配以“bla”或类似“bla”开头的单词。

更新:我现在所做的,适用于少量输入,使用以下(SOLR 模式的片段):

<fieldtype name="text_ngrams" class="solr.TextField">
  <analyzer type="index">
        <tokenizer class="solr.WhitespaceTokenizerFactory"/>
        <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="1" catenateNumbers="1" catenateAll="0" splitOnCaseChange="0"/>
        <filter class="solr.LowerCaseFilterFactory"/>
        <filter class="solr.EdgeNGramFilterFactory" minGramSize="2" maxGramSize="15" side="front"/>
  </analyzer>
  <analyzer type="query">
        <tokenizer class="solr.WhitespaceTokenizerFactory"/>
        <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="0" catenateNumbers="0" catenateAll="0" splitOnCaseChange="0"/>
        <filter class="solr.LowerCaseFilterFactory"/>
  </analyzer>

如果您不使用 SOLR,则执行以下操作。

Indextime:通过创建一个包含我的(短)输入的所有前缀的字段来索引数据。

Searchtime:仅使用 ~ 运算符,因为前缀明确存在于索引中。

4

4 回答 4

8

在 lucene 的开发主干(尚未发布)中,有代码通过 AutomatonQuery 支持这样的用例。警告:API 可能/将会在发布之前发生变化,但它为您提供了思路。

这是您的案例的示例:

// a term representative of the query, containing the field. 
// the term text is not so important and only used for toString() and such
Term term = new Term("yourfield", "bla~*");

// builds a DFA that accepts all strings within an edit distance of 2 from "bla"
Automaton fuzzy = new LevenshteinAutomata("bla").toAutomaton(2);

// concatenate this DFA with another DFA equivalent to the "*" operator
Automaton fuzzyPrefix = BasicOperations.concatenate(fuzzy, BasicAutomata.makeAnyString());

// build a query, search with it to get results.
AutomatonQuery query = new AutomatonQuery(term, fuzzyPrefix);
于 2010-05-08T03:16:53.867 回答
2

我不相信 Lucene 支持这样的东西,也不相信它有一个简单的解决方案。

“模糊”搜索不会对固定数量的字符进行操作。bla~例如可能匹配blah,因此它必须考虑整个术语。

您可以做的是实现一个查询扩展算法,该算法将查询bla~*转换为一系列 OR 查询

bla* OR blb* OR blc OR .... etc.

但这只有在字符串很短或者您可以根据某些规则缩小扩展范围时才真正可行。

或者,如果前缀的长度是固定的,您可以添加一个带有子字符串的字段并对其执行模糊搜索。这会给你你想要的,但只有当你的用例足够窄时才会起作用。

您没有具体说明为什么需要这个,也许这样做会引出其他解决方案。

我能想到的一种情况是处理不同形式的单词。例如寻找carcars

这在英语中很容易,因为有可用的词干分析器。在其他语言中,即使不是不可能,也很难实现词干分析器。

但是,在这种情况下,您可以(假设您可以访问一本好的词典)查找搜索词并以编程方式扩展搜索以搜索该词的所有形式。

例如,搜索cars被翻译成car OR cars. 这已在至少一个搜索引擎中成功应用于我的语言,但显然实现起来并不简单。

于 2010-04-13T16:38:19.087 回答
1

这是一个地址搜索服务,我想根据部分输入和可能输入错误的街道名称/城市名称/等(任何组合)来建议地址。(想想 ajax,用户在文本字段中输入部分街道地址)

对于这种情况,建议的查询扩展可能不太可行,因为部分字符串(街道地址)可能变得比“短”长:)

正常化

我能想到的一种可能性是使用字符串“规范化”,而不是模糊搜索,并将其与通配符查询简单地结合起来。街道地址

"miklabraut 42, 101 reykjavík", 归一化后会变成"miklabrat 42 101 rekavik"

所以,像这样构建索引

1) 使用包含“标准化”版本的街道名称、城市名称等的记录构建索引,每个文档有一个街道地址(1 个或多个字段)。

并像这样搜索索引

2)规范化mikl reyk用于形成查询(即)的输入字符串(例如mik rek)。3) 使用通配符 op 执行搜索(即mik* AND rek*),将模糊部分排除在外。

如果归一化算法足够好,那会飞:)

于 2010-04-13T19:48:08.423 回答
0

你的意思是你希望结合通配符和模糊查询?您可以使用带有 OR 条件的布尔查询进行组合,例如:

BooleanQuery bq = new BooleanQuery();

Query q1 = //here goes your wildcard query
bq.Add(q1, BooleanClause...)

Query q2 = //here goes your fuzzy query
bq.Add(q2, BooleanClause...)
于 2010-04-13T16:40:51.640 回答