【问题标题】:Substring matching for product search产品搜索的子字符串匹配
【发布时间】:2017-10-16 10:03:32
【问题描述】:

我有一个产品数据库(用于足球),其中包含大约 5k 种产品。用于产品搜索的 Lucene 索引当前包含名称、类别、颜色和编号(ArtNo 和 EAN)。

问题的相关表格示例:

| 姓名 | 颜色 | ------------------------------------------ |耐克训练足球 |红黑| |耐克比赛足球 |黑白| ------------------------------------------

对于索引,我创建了一个自定义分析器,因此我可以扩展一个具有其他行为的 StandardAnalyzer。流的创建现在看起来像这样:

TokenStream result = new StandardTokenizer(Util.Version.LUCENE_29, reader );
result = new StandardFilter(result);
result = new LowerCaseFilter(result);
result = new StopFilter(true, result, stoptable );
return result;

分析器同时用于索引器和搜索器。

这是当前的搜索逻辑:

BooleanQuery booleanQuery = new BooleanQuery(true);
string[] terms = query.Split(' ');

foreach (string s in terms)
{
  BooleanQuery subQuery = new BooleanQuery(true);

  var nameQuery = new FuzzyQuery(new Term("Name", s), 0.9f);
  nameQuery.SetBoost(6);
  subQuery.Add(nameQuery, BooleanClause.Occur.SHOULD);

  var colorQuery = new TermQuery(new Term("Color", s));
  subQuery.Add(colorQuery, BooleanClause.Occur.SHOULD);

  var categoryQuery = new FuzzyQuery(new Term("Category", s), 0.9f);
  categoryQuery.SetBoost(2);
  subQuery.Add(categoryQuery, BooleanClause.Occur.SHOULD);

  var numbersQuery = new TermQuery(new Term("Numbers", s));
  numbersQuery.SetBoost(10);
  subQuery.Add(numbersQuery, BooleanClause.Occur.SHOULD);

  booleanQuery.Add(subQuery, BooleanClause.Occur.MUST);
}

它已经以某种方式工作了。

问题:

许多产品的名称或类别都包含用户不会搜索的字词。 在示例中,我使用了“Nike Match football”。 (注意:我只翻译了它以用于 SO,因为数据库中的大多数术语都是德语)

如果我搜索“Nike football red”,我会得到结果。但如果搜索“Nike ball red”我不明白,尽管这是用户搜索它的方式。 Afaik Lucene 无法搜索子字符串(通配符除外),因为它只比较标记 - 我确实需要这样的东西。

我已将Name 和Category 模糊化,并根据其相关性对每一列进行了适当的提升。

我已经阅读了Ngrams,但是我真的不知道如何正确使用它。当我将NGramTokenFilter 添加到我的自定义分析器时,索引器工作。这里的问题是,我不希望每一列都使用它(只是名称和类别),并且在激活它时结果非常奇怪。

如果我将result = new NGramTokenFilter(result, 3, 4); 添加到我的分析器并搜索“nike ball”,它只会返回任何内容。

Ngrams 是这里的解决方案吗?我做错了什么?

对于如何改进产品搜索,您还有其他建议吗?

【问题讨论】:

  • 你用什么样的字段来索引?
  • 您应该注意,除非您使用 QueryParser,否则您的分析器不会应用于您的查询。手动构建的查询不会被分析,正如您必须自己拆分空格而不是让分析器处理这一事实所表明的那样。

标签: lucene lucene.net


【解决方案1】:

我不熟悉 Ngrams,但我看到你的情况有两种方法:

1.在搜索中使用通配符

在您喜欢搜索的字段上使用前缀或模糊查询。重要的是您使用 TextField ( Javadoc) 因为该字段将被分析(StringField 不要)并用于全文搜索。基于此,应该可以使用多个不完全匹配的术语进行搜索。

2。针对不同领域使用不​​同的分析器

您可以使用 PerFieldAnalyzerWrapper Javadoc 使用不同的分析器分析不同的字段。定义应该使用哪个分析器分析哪个字段,然后您就可以开始了。 但请注意,您使用相同的分析器进行索引和搜索(这是 lucene 最佳实践)

其他信息

如果您使用通配符和变音符号(德语 yaaaay),您必须知道通配符查询不会像普通查询那样被分析。 我遇到了同样的问题并用两种字段解决了它:

  • “规范化”(保存时不带变音符号 -> 转换为基本拉丁语 带有分析器的字符)
  • “非规范化”(用元音变音保存)

在这两个字段上搜索 BooleanQuery 时。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-14
    相关资源
    最近更新 更多