当前位置导航:炫浪网>>网络学院>>编程开发>>JAVA教程>>J2EE

基于开源搜索引擎的架构设计和J2EE实现(二)

  第四章 基于lucene的索引与搜索

  4.1什么是Lucene全文检索

  Lucene是Jakarta Apache的开源项目。它是一个用Java写的全文索引引擎工具包,可以方便的嵌入到各种应用中实现针对应用的全文索引/检索功能。

  4.2 Lucene的原理分析

  4.2.1全文检索的实现机制

  Lucene的API接口设计的比较通用,输入输出结构都很像数据库的表==>记录==>字段,所以很多传统的应用的文件、数据库等都可以比较方便的映射到Lucene的存储结构和接口中。

  总体上看:可以先把Lucene当成一个支持全文索引的数据库系统。

  索引数据源:doc(field1,field2...) doc(field1,field2...)

  \ indexer /

  _____________

  | Lucene Index|

  --------------

  / searcher 结果输出:Hits(doc(field1,field2) doc(field1...))

  Document:一个需要进行索引的“单元”,一个Document由多个字段组成

  Field:字段

  Hits:查询结果集,由匹配的Document组成

  4.2.2 Lucene的索引效率

  通常书籍后面常常附关键词索引表(比如:北京:12, 34页,上海:3,77 页……),它能够帮助读者比较快地找到相关内容的页码。而数据库索引能够大大提高查询的速度原理也是一样,想像一下通过书后面的索引查找的速度要比一页一 页地翻内容高多少倍……而索引之所以效率高,另外一个原因是它是排好序的。对于检索系统来说核心是一个排序问题。

  由于数据库索引不是为全文索引设计的,因此,使用like "%keyword%"时,数据库索引是不起作用的,在使用like查询时,搜索过程又变成类似于一页页翻书的遍历过程了,所以对于含有模糊查询的数据库 服务来说,LIKE对性能的危害是极大的。如果是需要对多个关键词进行模糊匹配:like"%keyword1%" and like "%keyword2%" ...其效率也就可想而知了。所以建立一个高效检索系统的关键是建立一个类似于科技索引一样的反向索引机制,将数据源(比如多篇文章)排序顺序存储的同 时,有另外一个排好序的关键词列表,用于存储关键词==>文章映射关系,利用这样的映射关系索引:[关键词==>出现关键词的文章编号,出现 次数(甚至包括位置:起始偏移量,结束偏移量),出现频率],检索过程就是把模糊查询变成多个可以利用索引的精确查询的逻辑组合的过程。从而大大提高了多 关键词查询的效率,所以,全文检索问题归结到最后是一个排序问题。

  由此可以看出模糊查询相对数据库的精确查询是一个非常不确定的问题,这也是大部分数据库对全文检索支持有限的原因。Lucene最核心的特征是通过特殊的索引结构实现了传统数据库不擅长的全文索引机制,并提供了扩展接口,以方便针对不同应用的定制。

  可以通过一下表格对比一下数据库的模糊查询:

  Lucene全文索引引擎 数据库

  索引 将数据源中的数据都通过全文索引一一建立反向索引 对于LIKE查询来说,数据传统的索引是根本用不上的。数据需要逐个便利记录进行GREP式的模糊匹配,比有索引的搜索速度要有多个数量级的下降。

  匹配效果 通过词元(term)进行匹配,通过语言分析接口的实现,可以实现对中文等非英语的支持。 使用:like "%net%" 会把netherlands也匹配出来,

  多个关键词的模糊匹配:使用like "%com%net%":就不能匹配词序颠倒的xxx.net..xxx.com

  匹配度 有匹配度算法,将匹配程度(相似度)比较高的结果排在前面。 没有匹配程度的控制:比如有记录中net出现5词和出现1次的,结果是一样的。

  结果输出 通过特别的算法,将最匹配度最高的头100条结果输出,结果集是缓冲式的小批量读取的。 返回所有的结果集,在匹配条目非常多的时候(比如上万条)需要大量的内存存放这些临时结果集。

  可定制性 通过不同的语言分析接口实现,可以方便的定制出符合应用需要的索引规则(包括对中文的支持) 没有接口或接口复杂,无法定制

  结论 高负载的模糊查询应用,需要负责的模糊查询的规则,索引的资料量比较大 使用率低,模糊匹配规则简单或者需要模糊查询的资料量少

  4.2.3 中文切分词机制

  对于中文来说,全文索引首先还要解决一个语言分析的问题,对于英文来说,语句中单词之间是天然通过空格分开的,但亚洲语言的中日韩文语句中的字是一个字挨一个,所有,首先要把语句中按“词”进行索引的话,这个词如何切分出来就是一个很大的问题。

  首先,肯定不能用单个字符作(si-gram)为索引单元,否则查“上海”时,不能让含有“海上”也匹配。但一句话:“北京天安门”,计算机如何按照中文的语言习惯进行切分呢?“北京 天安门” 还是“北 京 天安门”?让计算机能够按照语言习惯进行切分,往往需要机器有一个比较丰富的词库才能够比较准确的识别出语句中的单词。另外一个解决的办法是采用自动切分算法:将单词按照2元语法(bigram)方式切分出来,比如:"北京天安门" ==> "北京 京天 天安 安门"。这样,在查询的时候,无论是查询"北京" 还是查询"天安门",将查询词组按同样的规则进行切分:"北京","天安安门",多个关键词之间按与"and"的关系组合,同样能够正确地映射到相应的索引中。这种方式对于其他亚洲语言:韩文,日文都是通用的。

  基于自动切分的最大优点是没有词表维护成本,实现简单,缺点是索引效率低,但对于中小型应用来说,基于2元语法的切分还是够用的。基于2元切分后的索引一般大小和源文件差不多,而对于英文,索引文件一般只有原文件的30%-40%不同,

  自动切分 词表切分

  实现 实现非常简单 实现复杂

  查询 增加了查询分析的复杂程度, 适于实现比较复杂的查询语法规则

  存储效率 索引冗余大,索引几乎和原文一样大 索引效率高,为原文大小的30%左右

  维护成本 无词表维护成本 词表维护成本非常高:中日韩等语言需要分别维护。

  还需要包括词频统计等内容

  适用领域 嵌入式系统:运行环境资源有限

  分布式系统:无词表同步问题

  多语言环境:无词表维护成本 对查询和存储效率要求高的专业搜索引擎

  4.3 Lucene与Spider的结合

  首先构造一个Index类用来实现对内容进行索引。

  代码分析如下:


  1. package  news;   
  2. /**   
  3. * 新闻搜索引擎   
  4. * 计算机99630 沈晨   
  5. * 版本1.0   
  6. */    
  7. import  java.io.IOException;   
  8. import  org.apache.lucene.analysis.cn.ChineseAnalyzer;   
  9. import  org.apache.lucene.document.Document;   
  10. import  org.apache.lucene.document.Field;   
  11. import  org.apache.lucene.index.IndexWriter;   
  12. public   class  Index {   
  13. IndexWriter _writer =  null ;   
  14. Index()  throws  Exception {   
  15. _writer =  new  IndexWriter( "c:\\News\\index" ,   
  16. new  ChineseAnalyzer(),  true );   
  17. }   
  18. /**   
  19. * 把每条新闻加入索引中   
  20. * @param url 新闻的url   
  21. * @param title 新闻的标题   
  22. * @throws java.lang.Exception   
  23. */    
  24. void  AddNews(String url, String title)  throws  Exception {   
  25. Document _doc =  new  Document();   
  26. _doc.add(Field.Text( "title" , title));   
  27. _doc.add(Field.UnIndexed( "url" , url));   
  28. _writer.addDocument(_doc);   
  29. }   
  30. /**   
  31. * 优化并且清理资源   
  32. * @throws java.lang.Exception   
  33. */    
  34. void  close()  throws  Exception {   
  35. _writer.optimize();   
  36. _writer.close();   
  37. }   
  38. }   

  然后构造一个HTML解析类,把通过bot程序收集的新闻内容进行索引。

  代码分析如下:

  1. package  news;   
  2. /**   
  3. * 新闻搜索引擎   
  4. * 计算机99630 沈晨   
  5. * 版本1.0   
  6. */    
  7. import  java.util.Iterator;   
  8. import  java.util.Vector;   
  9. import  com.heaton.bot.HTMLPage;   
  10. import  com.heaton.bot.HTTP;   
  11. import  com.heaton.bot.Link;   
  12. public   class  HTMLParse {   
  13. HTTP _http =  null ;   
  14. public  HTMLParse(HTTP http) {   
  15. _http = http;   
  16. }   
  17. /**   
  18. * 对Web页面进行解析后建立索引   
  19. */    
  20. public   void  start() {   
  21. try  {   
  22. HTMLPage _page =  new  HTMLPage(_http);   
  23. _page.open(_http.getURL(),  null );   
  24. Vector _links = _page.getLinks();   
  25. Index _index =  new  Index();   
  26. Iterator _it = _links.iterator();   
  27. int  n =  0 ;   
  28. while  (_it.hasNext()) {   
  29. Link _link = (Link) _it.next();   
  30. String _herf = input(_link.getHREF().trim());   
  31. String _title = input(_link.getPrompt().trim());   
  32. _index.AddNews(_herf, _title);   
  33. n++;   
  34. }   
  35. System.out.println( "共扫描到"  + n +  "条新闻" );   
  36. _index.close();   
  37. }   
  38. catch  (Exception ex) {   
  39. System.out.println(ex);   
  40. }   
  41. }   
  42. /**   
  43. * 解决java中的中文问题   
  44. * @param str 输入的中文   
  45. * @return 经过解码的中文   
  46. */    
  47. public   static  String input(String str) {   
  48. String temp =  null ;   
  49. if  (str !=  null ) {   
  50. try  {   
  51. temp =  new  String(str.getBytes( "ISO8859_1" ));   
  52. }   
  53. catch  (Exception e) {   
  54. }   
  55. }   
  56. return  temp;   
  57. }   
  58. }   
共2页 首页 上一页 1 2 下一页 尾页 跳转到
相关内容
赞助商链接