【问题标题】:Lucene.net range queries + highlightingLucene.net 范围查询 + 突出显示
【发布时间】:2011-12-01 13:07:16
【问题描述】:

另一个 Lucene.net 问题由一个极端新手提出。

这一次,我发现了一个有趣的问题,即使用包含范围的查询并使用突出显示。

我是凭记忆写的,所以请原谅任何语法错误。

我有一个假设的 Lucene 索引:

---------------------------------------------------------
|       date         |               text               |
---------------------------------------------------------
|     1317809124     |       a crazy block of text      |
---------------------------------------------------------
|     1317809284     |       programmers are crazy      |
---------------------------------------------------------

** date is a unix timestamp        

...它们已通过以下方式添加到索引中:

Lucene.Net.Documents.Document doc = new Lucene.Net.Documents.Document();
doc.Add(new Lucene.Net.Documents.Field("text", "some block of text", Lucene.Net.Documents.Field.Store.YES, Lucene.Net.Documents.Field.Index.ANALYZED, Lucene.Net.Documents.Field.TermVector.WITH_POSITIONS_OFFSETS));
doc.Add(new Lucene.Net.Documents.Field("date", "some unix timestamp", Lucene.Net.Documents.Field.Store.YES, Lucene.Net.Documents.Field.Index.NOT_ANALYZED));

这就是我查询 Lucene 的方式:

Lucene.Net.Analysis.Standard.StandardAnalyzer analyzer = new Lucene.Net.Analysis.Standard.StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29);
Lucene.Net.Search.IndexSearcher searcher = new Lucene.Net.Search.IndexSearcher(Lucene.Net.Store.FSDirectory.Open(_headlinesDirectory), true);
Lucene.Net.QueryParsers.QueryParser parser = new Lucene.Net.QueryParsers.QueryParser(Lucene.Net.Util.Version.LUCENE_29, "text", analyzer);
Lucene.Net.Search.Query query = parser.Parse(queryPhrase);
Lucene.Net.Search.Hits hits = searcher.Search(query);

// code highlighting
Lucene.Net.Highlight.Formatter formatter = new Lucene.Net.Highlight.SimpleHTMLFormatter("<span style=\"background:yellow;\">","</span>");
Lucene.Net.Highlight.SimpleFragmenter fragmenter = new Lucene.Net.Highlight.SimpleFragmenter(50);
Lucene.Net.Highlight.QueryScorer scorer = new Lucene.Net.Highlight.QueryScorer(query);
Lucene.Net.Highlight.Highlighter highlighter = new Lucene.Net.Highlight.Highlighter(formatter, scorer);
highlighter.SetTextFragmenter(fragmenter);     

for (int i = 0; i < hits.Length(); i++)
{
    Lucene.Net.Documents.Document doc = hits.Doc(i);
    Lucene.Net.Analysis.TokenStream stream = analyzer.TokenStream("", new StringReader(doc.Get("text")));
    string highlightedText = highlighter.GetBestFragments(stream, doc.Get("text"), 1, "...");
    Console.WriteLine("--> " + highlightedText);
}

这是我的查询示例:

crazy AND date:[1286273266 TO 32503680000]

查询时,它会找到“疯狂”的所有结果,但不输出任何突出显示的文本。

当日期范围被删除并且您只需查询该术语时:

crazy

...这次突出显示正常工作。

在我的实现中我做错了什么,我应该寻找一个新的实现,还是这是一个已知的问题,可能会变通。

提前感谢stackeroverflow'ers :)

-- 编辑--

我已经实施了 LB 的建议(令人惊叹的顺便说一句!)。我仍然不知道为什么会这样,因为我认为 Lucene 完全是巫术或编程巫术,但确实如此,我很高兴 :)。

为了完整起见,这里是修改后的代码:

Lucene.Net.Analysis.Standard.StandardAnalyzer analyzer = new Lucene.Net.Analysis.Standard.StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29);
Lucene.Net.Search.IndexSearcher searcher = new Lucene.Net.Search.IndexSearcher(Lucene.Net.Store.FSDirectory.Open(_headlinesDirectory), true);
Lucene.Net.QueryParsers.QueryParser parser = new Lucene.Net.QueryParsers.QueryParser(Lucene.Net.Util.Version.LUCENE_29, "text", analyzer);

// new line here
parser.SetMultiTermRewriteMethod(Lucene.Net.Search.MultiTermQuery.SCORING_BOOLEAN_QUERY_REWRITE);

Lucene.Net.Search.Query query = parser.Parse(queryPhrase);

// new line here
Lucene.Net.Search.Query query2 = query.Rewrite(searcher.GetIndexReader());
Lucene.Net.Search.Hits hits = searcher.Search(query);

// code highlighting
Lucene.Net.Highlight.Formatter formatter = new Lucene.Net.Highlight.SimpleHTMLFormatter("<span style=\"background:yellow;\">","</span>");
Lucene.Net.Highlight.SimpleFragmenter fragmenter = new Lucene.Net.Highlight.SimpleFragmenter(50);

// changed to use query2
Lucene.Net.Highlight.QueryScorer scorer = new Lucene.Net.Highlight.QueryScorer(query2);

Lucene.Net.Highlight.Highlighter highlighter = new Lucene.Net.Highlight.Highlighter(formatter, scorer);
highlighter.SetTextFragmenter(fragmenter);

for (int i = 0; i < hits.Length(); i++)
{
    Lucene.Net.Documents.Document doc = hits.Doc(i);
    Lucene.Net.Analysis.TokenStream stream = analyzer.TokenStream("", new StringReader(doc.Get("text")));
    string highlightedText = highlighter.GetBestFragments(stream, doc.Get("text"), 1, "...");
    Console.WriteLine("--> " + highlightedText);
}

如果可以的话,请告诉我我是否准确地实施了这些建议。

【问题讨论】:

  • 不,这不是伏都教。这个技巧只是通过使用 indexreader 扩展术语,将 PrefixQuery 或 RangeQuery 等多术语查询转换为布尔查询。假设您在索引 aaa1 和 aaa2 中有两个术语。像 text:aaa* (这是一个 PrefixQuery)这样的查询将扩展为 (text:aaa1 text:aaa2)。您可以使用 query.ToString() 函数自行测试。
  • 感谢您的解释和解决方案。由于像您这样的人提供的惊人提示,我正在减慢 Lucene.NET 解决方案的工作速度。再次欢呼和感谢。

标签: c# .net lucene lucene.net


【解决方案1】:

首先调用QueryParser的

SetMultiTermRewriteMethod(MultiTermQuery.SCORING_BOOLEAN_QUERY_REWRITE)

方法,然后创建一个新查询为

Query newQuery = query.Rewrite(indexReader);

现在您可以使用“newQuery”进行搜索。

【讨论】:

  • 我需要使用什么样的 indexReader 来进行这个 rewrite 调用?
  • @lurscher,你应该已经有一个 IndexReader。要么您通过new IndexSearcher(indexReader)new IndexSearcher(dir) 创建了indexSearcher,在这种情况下您可以通过searcher.GetIndexReader 获得读者
猜你喜欢
  • 2012-08-02
  • 1970-01-01
  • 1970-01-01
  • 2010-10-04
  • 2010-12-10
  • 2011-09-08
  • 2022-01-16
  • 1970-01-01
  • 2011-10-09
相关资源
最近更新 更多