lucene.net 2.0 中文分词后语法高亮问题

lucene.net 2.0  src包里自带了Highlighter.Net-2.0.0,可以用来实现语法高亮。

    //定义多条件搜索分析器
  BooleanQuery bquery = new BooleanQuery();
   //定义分词器
   Analyzer analyzer  = new StandardAnalyzer();

   //多条件搜索拆分器
            MultiFieldQueryParser parser = new MultiFieldQueryParser(new string[] { "title", "content" }, analyzer);
            query = parser.Parse(key);
            bquery.Add(query, BooleanClause.Occur.MUST);
               
            DateTime now = DateTime.Now;
   //初始化搜索器
   //实现分布式搜索
   List<IndexReader> indexreaders = new List<IndexReader>();
   string[] dirs = Directory.GetDirectories(dir);
   if (searchtype == SearchType.None)
   {
    foreach (string item in dirs)
    {
     //System.Web.HttpContext.Current.Response.Write(item);
     indexreaders.Add(IndexReader.Open(Path.Combine(Path.Combine(dir, item), "Save")));
    }
   }
   else
   {
    //System.Web.HttpContext.Current.Response.Write(searchtype.ToString());
    indexreaders.Add(IndexReader.Open(Path.Combine(Path.Combine(dir, searchtype.ToString()), "Save")));
   }

   MultiReader reader = new MultiReader(indexreaders.ToArray());
   indexSearcher = new IndexSearcher(reader);

   Hits hits = null;
   hits = indexSearcher.Search(bquery);
   timer = (DateTime.Now - now).TotalMilliseconds;

 int count = hits.Length();
   
            /* 计算显示的条目 */
      int       start = (pageNo - 1) * 10;
      int       end = pageNo * 10 > count ? count : pageNo * 10;
            //Response.Write(readerhelper.MyQuery.ToString());
            /* 语法高亮显示设置 */
         Highlighter        highlighter = new Highlighter(new QueryScorer(query ));
       highlighter.SetTextFragmenter(new SimpleFragmenter(100));

for (int i = start; i < end; i++)
{
     Lucene.Net.Documents.Document doc = hits.Doc(i);
              System.String text = doc.Get("content");
     //添加结尾,保证结尾特殊符号不被过滤
              string title = doc.Get("title") + "+aaaaaaaaa";
     Lucene.Net.Analysis.TokenStream tokenStream = analyzer  .TokenStream("content", new System.IO.StringReader(text));
     Lucene.Net.Analysis.TokenStream titkeStream = analyzer .TokenStream("title", new System.IO.StringReader(title));
     System.String result = highlighter.GetBestFragments(tokenStream, text, 2, "...");
     string tresult = highlighter.GetBestFragments(titkeStream, title, 0, "..");
     //祛除标题结尾标记
     if (tresult.Length > 10)
      tresult = tresult.Remove(tresult.Length - 10, 10);
     if (string.IsNullOrEmpty(tresult))
      tresult = title.Remove(title.Length - 10, 10);
     //未标注内容读取
     if (string.IsNullOrEmpty(result))
     {
      if (text.Length > 100)
       result = text.Substring(0, 100);
      else
       result = text;
     }
     if (result.Length < text.Length)
      result = result + "...";
}

这是使用lucene.net的自带分词器StandardAnalyzer,有个弊端是一个字就认为是一个词。现在我们要用自己的中文词义分词器——MyAnalyzer的话,问题来了。Highlighter一直报错。为什么会出现这种情况呢?那是因为,中文分词器,分词完成一般有分割符号。比如,对于词“沪江英语”,分割完成后变成"沪江 英语"。也就是说,返回的Token是(沪江,0,2)(英语,3,5)。而如果用Highlighter,它想要取得词是(沪江,0,2)(英语,2,4),这个就是因为空格而产生的偏差,引起了Highlighter的报错。修改Highlighter比较麻烦,要对分词器做特殊处理也比较难。可以使用字典解释器,分割结果后再高亮。比如,取得"沪江英语"的分词结果"沪江 英语",然后,把分词结果传递给Highlighter。弊端是,搜索结果会凭空出现很多空格。俺们懒人自然有懒人的解决办法。那就是用MyAnalyzer实现索引和搜索,用StandardAnalyzer实现高亮:

    //定义多条件搜索分析器
  BooleanQuery bquery = new BooleanQuery();
   //定义分词器
   Analyzer analyzer  = new MyAnalyzer();
  Analyzer highanalyzer  = new StandardAnalyzer();
MultiFieldQueryParser parser = new MultiFieldQueryParser(new string[] { "title", "content" }, highanalyzer );
Query highquery = parser .Parse(key);

   //多条件搜索拆分器
            MultiFieldQueryParser parser = new MultiFieldQueryParser(new string[] { "title", "content" }, analyzer);
            query = parser.Parse(key);
            bquery.Add(query, BooleanClause.Occur.MUST);
               
            DateTime now = DateTime.Now;
   //初始化搜索器
   //实现分布式搜索
   List<IndexReader> indexreaders = new List<IndexReader>();
   string[] dirs = Directory.GetDirectories(dir);
   if (searchtype == SearchType.None)
   {
    foreach (string item in dirs)
    {
     //System.Web.HttpContext.Current.Response.Write(item);
     indexreaders.Add(IndexReader.Open(Path.Combine(Path.Combine(dir, item), "Save")));
    }
   }
   else
   {
    //System.Web.HttpContext.Current.Response.Write(searchtype.ToString());
    indexreaders.Add(IndexReader.Open(Path.Combine(Path.Combine(dir, searchtype.ToString()), "Save")));
   }

   MultiReader reader = new MultiReader(indexreaders.ToArray());
   indexSearcher = new IndexSearcher(reader);

   Hits hits = null;
   hits = indexSearcher.Search(bquery);
   timer = (DateTime.Now - now).TotalMilliseconds;

 int count = hits.Length();
   
            /* 计算显示的条目 */
      int       start = (pageNo - 1) * 10;
      int       end = pageNo * 10 > count ? count : pageNo * 10;
            //Response.Write(readerhelper.MyQuery.ToString());
            /* 语法高亮显示设置 */
         Highlighter        highlighter = new Highlighter(new QueryScorer(highquery));
       highlighter.SetTextFragmenter(new SimpleFragmenter(100));

for (int i = start; i < end; i++)
{
     Lucene.Net.Documents.Document doc = hits.Doc(i);
              System.String text = doc.Get("content");
     //添加结尾,保证结尾特殊符号不被过滤
              string title = doc.Get("title") + "+aaaaaaaaa";
     Lucene.Net.Analysis.TokenStream tokenStream = highanalyzer  .TokenStream("content", new System.IO.StringReader(text));
     Lucene.Net.Analysis.TokenStream titkeStream = highanalyzer  .TokenStream("title", new System.IO.StringReader(title));
     System.String result = highlighter.GetBestFragments(tokenStream, text, 2, "...");
     string tresult = highlighter.GetBestFragments(titkeStream, title, 0, "..");
     //祛除标题结尾标记
     if (tresult.Length > 10)
      tresult = tresult.Remove(tresult.Length - 10, 10);
     if (string.IsNullOrEmpty(tresult))
      tresult = title.Remove(title.Length - 10, 10);
     //未标注内容读取
     if (string.IsNullOrEmpty(result))
     {
      if (text.Length > 100)
       result = text.Substring(0, 100);
      else
       result = text;
     }
     if (result.Length < text.Length)
      result = result + "...";
}
这样的结果还是很友好的,例如:
http://so.yeshj.com/so.aspx?key=%E6%B2%AA%E6%B1%9F%E6%97%A5%E8%AF%AD&h=%E6%B2%AA%E6%B1%9F%E6%97%A5%E8%AF%AD
全文完。

posted @ 2008-02-26 19:00 Birdshover 阅读(4477) 评论(17)  编辑 收藏 网摘

  回复  引用  查看    
#1楼2008-02-26 20:47 | Jeffrey Zhao      
其实着色不难,中文分词是关键,结构化数据和非结构化数据一起搜索是最难办的……
  回复  引用    
#2楼2008-02-26 21:47 | puserchen[未注册用户]
赞同楼上的说法,中文分词,智能识别结构与非结构,这个是关键,当然博主做到这么细,也是值得赞的
  回复  引用    
#3楼2008-02-27 09:48 | yingzi2[未注册用户]
StandardAnalyzer LZ,你这是你一字一个字分的.....
  回复  引用    
#4楼2008-02-28 10:29 | pwqzc[未注册用户]
楼主的分词速度太慢!
  回复  引用    
#5楼2008-02-28 11:21 | Intermapper[未注册用户]
速度有些慢!
  回复  引用  查看    
#6楼2008-03-03 17:14 | 阿瑞--16hi      
那改怎么优化呢?

  回复  引用    
#7楼2008-06-25 12:37 | lucene[未注册用户]
错误 1 间接引用了包含“Lucene.Net.Highlight.QueryScorer.New”的 2.1.0.3 版程序集 Lucene.Net。此项目引用 2.0.0.4 版 Lucene.Net 以前的版本。要使用“Lucene.Net.Highlight.QueryScorer.New”,必须将对 Lucene.Net 的引用替换为对 2.1.0.3 版或更高版本的引用。

这个怎么办?我没有找到2.1.0.3 版程序集 Lucene.Net啊

  回复  引用  查看    
#8楼[楼主]2008-06-27 17:29 | BirdsHover      
@lucene
更新下版本就可以了

  回复  引用    
#9楼2008-08-18 18:01 | 陈草原[未注册用户]
LZ :我没有Analyzer analyzer = new MyAnalyzer();
MyAnalyzer 怎么来?

  回复  引用  查看    
#10楼2008-09-01 09:58 | yuejianjun      
我们公司网站好像用Chocobo3来实现分词的。
一直想学一下Lucene.Net分词,你那个有没有一个DEMO啊,能不能上传上来或发给我参考一下?谢谢

  回复  引用    
#11楼2008-12-07 10:51 | gxhui[未注册用户]
为什么我的BooleanQuery加入WildcardQuery,RangeQuery后只显示标题,内容不在,且关键字不以高亮显示!如果去了WildcardQuery,RangeQuery中的MUST条件后显示正常!
  回复  引用    
#12楼2008-12-07 10:55 | gxhui[未注册用户]
主要代码如示:请高手们指点!
Analyzer analyzer=new StandardAnalyzer();//对要查询词汇的智能解析
BooleanQuery boolQuery=new BooleanQuery();//还有个进行多条件搜索and 与 or 的操作————

//内置提供了很多语法来使使用可以输入各种高级条件的Query。比如: "Hello AND world"会被解析为一个AND关系的BooleanQuery
if(location!=null&&location!=string.Empty)// 使用通配符搜索
{
boolQuery.Add(new WildcardQuery(new Term("Location",location+"*")),BooleanClause.Occur.MUST);//WildcardQuery:通配符搜索 ?
}///字段名和要搜索的字符串

if(minTime!=DateTime.MinValue)
{
boolQuery.Add(new RangeQuery(new Term("PostDate",DateField.DateToString(minTime)),null,false),BooleanClause.Occur.MUST);
}

MultiFieldQueryParser parser = new MultiFieldQueryParser(new string[] { "Title", "Content" }, analyzer);
//parser.SetDefaultOperator(QueryParser.Operator.AND);
Query query = parser.Parse(queryString);
boolQuery.Add(query, BooleanClause.Occur.MUST);

Highlighter highlighter=new Highlighter(new MyHTMLFormatter(),new QueryScorer(boolQuery));//用自定义的形式显示关键字
highlighter.SetTextFragmenter(new SimpleFragmenter(50));//这个50是指定关键字字符串的context的长度,你可以自己设定,因为不可能返回整篇正文内容

IndexSearcher searcher=new IndexSearcher(_newsIndexFolder);
Hits hits=searcher.Search(boolQuery);//用于保存结果集

  回复  引用  查看    
#13楼[楼主]2008-12-11 11:05 | Birdshover      
@gxhui
Highlighter 的内部是以Analyzer的结果来构造的,用这种特殊的Analyzer,里面可能解析不出来。你可以试着调试一下看看。

  回复  引用  查看    
#14楼[楼主]2008-12-11 11:05 | Birdshover      
@yuejianjun
我有写关于分词的一系列文章,你看看,也许对你有帮助

  回复  引用  查看    
#15楼[楼主]2008-12-11 11:06 | Birdshover      
@陈草原
MyAnalyzer是自己做的一个分词器

  回复  引用  查看    
#16楼2009-03-11 15:02 | matchcolor      
用了高亮组件,搜索的速度太慢了
  回复  引用  查看    
#17楼2009-03-27 13:16 | 风之旖旎      
一直也调不出高亮,楼主的文章再好好看看



发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 1082739




相关文章:

相关链接: