【问题标题】:MultiFieldQueryParser and wildcardsMultiFieldQueryParser 和通配符
【发布时间】:2015-03-20 11:16:12
【问题描述】:

我正在尝试设置 lucene.net 3 以便能够在两个字段中搜索一个短语,但我遇到了困难。这是我希望查询返回的内容:

我希望查询返回完全匹配的词组,例如:

短语:“清云红舒缓草药膏”

结果:“清云红舒缓草药膏”

以及通配符匹配:

短语:“CHING WAN HUNG SOO”或“CHING WAN HUN”

结果:“CHING WAN HUNG SOOTHING HERBAL BALM”和其他可能匹配此短语或任何其他不完整短语的变体。

我最初的解决方案是创建一个布尔查询,其中包含短语查询和解析和通配符每个单词的查询。

但这会返回匹配项以及太多不接近适用的结果。 (它会返回“HERBAL TEA”,因为“HERBAL”是解析后的术语之一……)由于解析了 OR 查询。

这与我的原始帖子有关:How to set up a query to return phrases and parts of phrases in lucene.net? 想知道是否可以在标准 Lucene.net 中执行此操作,而无需使用提到的 Java 端口。

有人可以给我任何指导吗? 谢谢!

public override List<TT> ExecuteSearch(string searchQuery, string searchField = "")
{
  if (string.IsNullOrEmpty(searchQuery.Replace("*", "").Replace("?", ""))) return new List<TT>();

  using (var searcher = new IndexSearcher(Directory, false))
  {
        var hits_limit = 1000;
        var analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30, new HashSet<string>());
        var fields = new[] {"CompositeName", "SubstanceName"};

        var parser = new MultiFieldQueryParser(Lucene.Net.Util.Version.LUCENE_30, fields, analyzer);
        parser.AllowLeadingWildcard = true;
        parser.PhraseSlop = 0;
        var query = ParseWholeQueryWc(searchQuery, fields, parser);
        searcher.SetDefaultFieldSortScoring(true, true);
        var hits = searcher.Search(query, null, hits_limit, Sort.RELEVANCE).ScoreDocs;
        var results = MapLuceneToDataList(hits, searcher);
        analyzer.Close();
        searcher.Dispose();
        return results;
  }
}

public Query ParseWholeQueryWc(string searchQuery, string[] fields, QueryParser parser)
{
  Query query = new PhraseQuery();
  Query query2 = new PhraseQuery();
  Query mq = new BooleanQuery();

  try
  {
        var bld = ParseTermWithWildcards(searchQuery);

        // phrase
        query = parser.Parse("\"" + searchQuery.Trim() + "\"");

        // or
        query2 = parser.Parse(searchQuery + "*");

        // main
        ((BooleanQuery)mq).Add(query, Occur.SHOULD);
        ((BooleanQuery)mq).Add(query2, Occur.SHOULD);
  }
  catch (ParseException ex)
  {
        throw;
  }
  return mq;
}

更新

    public BooleanQuery ParseWholeQueryWc(string searchQuery, string[] fields, QueryParser parser)
    {
        BooleanQuery mq = new BooleanQuery();

        try
        {
            string[] qrArr = searchQuery.Split(null);
            SpanQuery[] compNmQ = new SpanQuery[qrArr.Length];
            SpanQuery[] subsNmQ = new SpanQuery[qrArr.Length];

            for (var i = 0; i < qrArr.Length; i++)
            {
                //CompositeName", "SubstanceName
                if (i == qrArr.Length - 1)
                {
                    compNmQ[i] = new SpanTermQuery(new Term("CompositeName", qrArr[i] + "*"));
                    subsNmQ[i] = new SpanTermQuery(new Term("SubstanceName", qrArr[i] + "*"));
                }
                else
                {
                    compNmQ[i] = new SpanTermQuery(new Term("CompositeName", qrArr[i]));
                    subsNmQ[i] = new SpanTermQuery(new Term("SubstanceName", qrArr[i]));
                }
            }

            SpanQuery compNameQ = new SpanNearQuery(compNmQ, 0, true);
            SpanQuery subsNameQ = new SpanNearQuery(subsNmQ, 0, true);

            // main
            ((BooleanQuery) mq).Add(compNameQ, Occur.SHOULD);
            ((BooleanQuery)mq).Add(subsNameQ, Occur.SHOULD);
        }
        catch (ParseException ex)
        {
            throw new ArgumentException("BaseLuceneStrategy:ParseWholeQueryWc():" + ex.Message);
        }
        return mq;
    }

这将返回零命中。

【问题讨论】:

    标签: lucene lucene.net


    【解决方案1】:

    如果您只想要求所有条款,无论它们出现的顺序或接近程度如何,这是一个简单的解决方法。只需添加:

    parser.setDefaultOperator(QueryParser.Operator.AND);
    

    如果您的所有查询都将从您希望匹配的字段的开头开始,那么您可以将该字段更改为未分析。如果不对其进行分析,那么一个简单的通配符查询就可以完成这项工作。但是,如果您希望能够查询以下内容,这将不是一个好的解决方案:"HUNG SOOTHING HERBAL"


    另外,SpanQueries 可以帮助解决问题。这在 Java 中肯定更好,因为在 v3.1 中我们可以使用 SpanMultiTermQueryWrapper,但是在 v3.0.3(以及 .Net 端口)中,您可以使用 SpanRegexQuery

    SpanQuery[] subqueries = new SpanQuery[4];
    subqueries[0] = new SpanTermQuery(new Term("field", "CHING"));
    subqueries[1] = new SpanTermQuery(new Term("field", "WAN"));
    subqueries[2] = new SpanTermQuery(new Term("field", "HUNG"));
    subqueries[3] = new SpanRegexQuery(new Term("field", "SOO.*"));
    SpanQuery finalQuery = new SpanNearQuery(subqueries, 0, true)
    

    对任何其他字段执行相同操作,并将它们组合成一个 BooleanQuery

    【讨论】:

    • 感谢 femtoRgon,我创建了它,它现在返回零记录。我在原始帖子中根据您上面的建议添加了修改后的代码。
    • 可能是由于分析。请记住,分析器不会在这里的任何地方应用。看起来您正在使用 StandardAnalyzer,它将所有内容都小写,因此您需要将搜索字词小写。
    • 我降低了字符串并且效果很好。唯一的问题是,当我尝试搜索“CHING WAN HUNG SOOTHING HERBAL BA”或“CHING WAN HUNG SOOTHING HERBAL BAL”时,它的点击率为零。知道为什么吗?再次感谢您的回复。
    • 哦!我忘了包括通配符。只需一秒钟;)
    • 不幸的是,我仍然在部分单词 BAL 上得到零匹配,并附加了一个通配符。有什么想法吗?
    猜你喜欢
    • 1970-01-01
    • 2015-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-17
    • 1970-01-01
    • 2011-08-02
    • 1970-01-01
    相关资源
    最近更新 更多