1、16.1.1 Tika概述 Tika是一个文档语义信息分析工具,用于实现对文档的元信息是一个文档语义信息分析工具,用于实现对文档的元信息提取。它可自动识别文档类型,从各类文档中提取元信息,并可提取。它可自动识别文档类型,从各类文档中提取元信息,并可对内容进行分析生成文本串对内容进行分析生成文本串.Tika 的的parse 方法接受要被解析的文档,并将分析结果写入方法接受要被解析的文档,并将分析结果写入元数据集合中。以下为元数据集合中。以下为parse方法的最简单形态:方法的最简单形态:public void parse(InputStream stream,Metadata metadata)
2、;16.1.2 Lucene索引和搜索概述 Lucene提供查询和索引功能提供查询和索引功能Lucene采用倒排索引结构,以词作为索引的中心,建立词到采用倒排索引结构,以词作为索引的中心,建立词到文档的映射关系。文档的映射关系。Lucene自带有分词功能,自带有分词功能,lucene缺省提供了缺省提供了2个比较通用的分析器个比较通用的分析器SimpleAnalyzer和和StandardAnalyzer,中,中文分词则常用文分词则常用IK Analyzer,最新的版本是,最新的版本是IKAnalyzer2012.jar。可将下载的包中的可将下载的包中的IKAnalyzer.cfg.xml(配置
3、文件)和(配置文件)和stopword.dic(停用词典停用词典)放在工程的放在工程的src路径下,将路径下,将IKAnalyzer2012.jar复制到复制到web工程的工程的WEB-INF/lib目录下。目录下。Lucene的数据存储结构都很像数据库的表的数据存储结构都很像数据库的表=记录记录=字段,字段,Lucene索引文件中包索引文件中包含段(含段(segment)、文档()、文档(document)、)、域(域(field)和项()和项(term)。索引包含多个段,)。索引包含多个段,每个段包含多个文档,每个文档又包含多个域,每个段包含多个文档,每个文档又包含多个域,而每个域又包含多
4、个项。而每个域又包含多个项。搜索时,搜索引擎首先会对搜索的关键词进搜索时,搜索引擎首先会对搜索的关键词进行解析,然后再在建立好的索引上进行查找,行解析,然后再在建立好的索引上进行查找,最终返回和用户输入的关键词相关联的文档。最终返回和用户输入的关键词相关联的文档。16.1.3 Lucene 软件包分析Lucene 软件包是软件包是lucene-core-3.1.0.jarorg.apache.lucene.document包:被索引的文档对象的结构管理。提供了所需要包:被索引的文档对象的结构管理。提供了所需要的类,比如的类,比如 Document,Field。每一个文档最终被封装成了一个。每一
5、个文档最终被封装成了一个 Document 对象。对象。org.apache.lucene.analysis包:含语言分析器,也称分词器。用于把句子切分为包:含语言分析器,也称分词器。用于把句子切分为单个的关键词,支持中文分词。单个的关键词,支持中文分词。org.apache.lucene.index包:索引管理,主要功能是建立和删除索引。其中有两包:索引管理,主要功能是建立和删除索引。其中有两个基础的类:个基础的类:IndexWriter 和和 IndexReader。IndexWriter 是用来创建索引并是用来创建索引并添加文档到索引中,添加文档到索引中,IndexReader 可打开索
6、引,删除索引中的文档等。可打开索引,删除索引中的文档等。org.apache.lucene.search包:提供了对索引进行搜索所需要的类。常用的类有包:提供了对索引进行搜索所需要的类。常用的类有 IndexSearcher类含有在指定的索引上进行搜索的方法;类含有在指定的索引上进行搜索的方法;Hits 类用来保存搜索得类用来保存搜索得到的结果;到的结果;TopDocs类则为首页的搜索结果。类则为首页的搜索结果。org.apache.lucene.queryParser:查询分析器。支持对查询关键词进行逻辑运:查询分析器。支持对查询关键词进行逻辑运算。算。org.apache.lucene.s
7、tore:数据存储管理,用于实现底层的输入:数据存储管理,用于实现底层的输入/输出操作。输出操作。org.apache.lucene.util:含有一些工具类。:含有一些工具类。16.1.4 与索引创建相关的API Document:用来描述文档的,这里的文档可以是:用来描述文档的,这里的文档可以是HTML 页面,或者是页面,或者是文本文件等。文本文件等。Field:用来描述一个文档的某个属性,如标题和内容用两个:用来描述一个文档的某个属性,如标题和内容用两个 Field 对对象分别描述。象分别描述。Analyzer:在一个文档被索引之前,首先需要对文档内容进行分词处理,:在一个文档被索引之前
8、,首先需要对文档内容进行分词处理,该工作由该工作由 Analyzer完成。完成。Analyzer 类是一个抽象类,针对不同的文档类是一个抽象类,针对不同的文档类型,它有多个具体实现类。类型,它有多个具体实现类。Analyzer 把分词后的内容交给把分词后的内容交给 IndexWriter 进行索引。进行索引。IndexWriter:是用来创建索引的核心类,它将各个:是用来创建索引的核心类,它将各个Document 对象对象加到索引中。加到索引中。Directory:代表索引存储位置的一个抽象类,其子类:代表索引存储位置的一个抽象类,其子类FSDirectory和和RAMDirectory分别对
9、应文件系统和内存位置。前者适合于大索引,后分别对应文件系统和内存位置。前者适合于大索引,后者适用于速度相对较快的小索引。者适用于速度相对较快的小索引。16.1.5 与内容搜索相关的API IndexSearcher:是抽象类:是抽象类Searcher的一个常用子的一个常用子类,允许在给定的目录中搜索索引。其类,允许在给定的目录中搜索索引。其Search 方法方法可返回一个根据计算分数排序的文档集合。可返回一个根据计算分数排序的文档集合。Lucene在在收集结果的过程中将匹配度低的结果自动过滤掉。收集结果的过程中将匹配度低的结果自动过滤掉。Term:是搜索的基本单位。它由两部分组成:单词:是搜索
10、的基本单位。它由两部分组成:单词文本和出现该文本的字段名称。文本和出现该文本的字段名称。Query:是一个用于查询的抽象基类。它将用户输入:是一个用于查询的抽象基类。它将用户输入的查询字符串封装成的查询字符串封装成 Lucene 能够识别的能够识别的 Query对象。对象。常见子类有:常见子类有:TermQuery、BooleanQuery、PhraseQuery、PrefixQuery、RangeQuery、MultiTermQuery、FilteredQuery等。等。TopDocs:封装最顶部的若干搜索结果以及:封装最顶部的若干搜索结果以及 ScoreDoc 的总数。的总数。16.2 创
11、建索引1.文件项的封装设计文件项的封装设计package chapter16;public class FileItem String filename;String content;String title;./构造方法和各属性的构造方法和各属性的Setter和和Getter方法略方法略2.对指定目录的文档建立索引File indexDir=new File(e:index2);/索引存储位置索引存储位置Analyzer TextAnalyzer=new IKAnalyzer();/用用IKAnalyzer分词工分词工具具IndexWriterConfig fsConfig=new Inde
12、xWriterConfig(Version.LUCENE_31,TextAnalyzer);fsConfig.setOpenMode(OpenMode.CREATE);IndexWriter writer=new IndexWriter(new SimpleFSDirectory(indexDir),fsConfig);/见说明见说明(1)File dataDir=new File(f:caijava);/对该目录下文件建立索引对该目录下文件建立索引File dataFiles=dataDir.listFiles();/所有文件列表所有文件列表try LuceneIndexerExtended
13、 ie=new LuceneIndexerExtended(writer,new Tika();for(int i=0;i dataFiles.length;i+)String filetype=FileType(dataFilesi.getName();System.out.println(dataFilesi.getName();String allowtype=txt,html,doc,pdf,ppt;/限制要索引文档类型限制要索引文档类型if(allowtype.indexOf(filetype)!=-1)ie.indexContent(dataFilesi);/对各对各文件建立索引文
14、件建立索引对指定文件建索引public void indexContent(File file)/对指定文件建索引对指定文件建索引Metadata met=new Metadata();InputStream is;try is=new FileInputStream(file);tika.parse(is,met);/用用Tika分析提取文档的元数据分析提取文档的元数据Document document=new Document();document.add(new Field(filename,file.getName(),Store.YES,Index.ANALYZED);/文档名称文档
15、名称document.add(new Field(title,met.get(title),Store.YES,Index.NOT_ANALYZED);/文档标题文档标题document.add(new Field(content,tika.parseToString(file),Store.YES,Index.ANALYZED);/文档内容文档内容writer.addDocument(document);is.close();catch(Exception e)16.3 建立基于Web的搜索服务public class SearcherService static IndexSearcher
16、 searcher;static Highlighter highlighter;static Analyzer me;public static TopDocs search(String queryStr)TopDocs topDocs=null;try File indexDir=new File(e:index2);FSDirectory directory=FSDirectory.open(indexDir);searcher=new IndexSearcher(directory);me=new IKAnalyzer();QueryParser m=new QueryParser(
17、Version.LUCENE_31,content,me);Query luceneQuery;luceneQuery=m.parse(queryStr);Filter filter=null;/以下创建高亮显示模板以下创建高亮显示模板SimpleHTMLFormatter shf=new SimpleHTMLFormatter(,);/以下构造高亮对象以下构造高亮对象highlighter=new Highlighter(shf,new QueryScorer(luceneQuery);highlighter.setTextFragmenter(new SimpleFragmenter(20
18、0);topDocs=searcher.search(luceneQuery,filter,50);catch(IOException e)System.out.println(e);catch(Exception e)System.out.println(e);return topDocs;public static List getPage(TopDocs topDocs,String key,int page)List items=new ArrayList();int pageSize=5;try int start=(page-1)*pageSize;int end=page*pag
19、eSize;ScoreDoc scoreDoc =topDocs.scoreDocs;if(end topDocs.scoreDocs.length)end=topDocs.scoreDocs.length;for(int index=start;index end;index+)Document doc=searcher.doc(scoreDocindex.doc);String title=doc.get(title);/文档标题文档标题String summary=highlighter.getBestFragment(me,content,doc.get(content);/提取文档摘
20、要,并对搜索词用高亮显示提取文档摘要,并对搜索词用高亮显示items.add(new FileItem(doc.get(filename),summary,title);catch(CorruptIndexException e)catch(IOException e)catch(InvalidTokenOffsetsException e)return items;3MVC控制器的代码RequestMapping(value=/index,method=RequestMethod.POST)public ModelAndView disp(RequestParam(keyword)Strin
21、g key)ModelMap dataModel=new ModelMap();TopDocs topDocs=SearcherService.search(key);List items=SearcherService.getPage(topDocs,key,1);dataModel.put(pages,(int)(Math.ceil(topDocs.scoreDocs.length/5.0);dataModel.put(keyword,key);dataModel.put(result,items);return new ModelAndView(/result,dataModel);/分
22、页分页RequestMapping(value=/index/pageid/key,method=RequestMethod.GET)public ModelAndView disp(PathVariable(pageid)String pageid,PathVariable(key)String key)ModelMap dataModel=new ModelMap();try key=new String(key.getBytes(ISO-8859-1),UTF-8);catch(UnsupportedEncodingException e)TopDocs topDocs=Searcher
23、Service.search(key);int page=Integer.parseInt(pageid);List items=SearcherService.getPage(topDocs,key,page);dataModel.put(pages,(int)(Math.ceil(topDocs.scoreDocs.length/5.0);dataModel.put(keyword,key);dataModel.put(result,items);return new ModelAndView(/result,dataModel);4显示视图form method=POST action=/index $dir.title$dir.content%int pages;if(request.getAttribute(pages)=null)pages=0;elsepages=Integer.parseInt(+request.getAttribute(pages);for(int k=1;ka href=/index/$keyword第第页页