在本教程中,将通过它们的核心概念(例如语法解析,MIME检测,内容分析法,索引,scoring方法,boosting方法)来解释Apache Lucene和Apache Tika框架,这些示例不仅适用于经验丰富的软件开发人员,还适用于内容分析法和编程的初学者。我们假设您具备Java™编程语言应用知识和大量可供分析的内容。
在本教程中,您将学习:
根据Apache Lucene的网站,Apache Lucene代表了一个开源的Java库,可被用于从大量文档集合中进行索引和搜索。索引大小约占索引文本大小的20-30%,搜索算法提供的功能如下:
但是Lucene的主要目的是直接处理文本,和我们想操作的具有各种格式和编码的文档。为了解析文档内容及其属性,Apache Tika库是必要的。
Apache Tika是一个库,它提供了一组灵活和强大的接口,可用于任何需要元数据分析和结构化文本提取的环境中。Apache Tika的关键组件是Parser(org.apache.tika.parser.Parser)接口,因为它隐藏了不同文件格式的复杂性,同时提供了一种简单而强大的机制来从各种文档中提取结构化文本内容和元数据。
Tika解析设计的标准
流式解析 | 该接口既不需要客户端应用程序也不需要解析器实现来将完整的文档内容保存在内存中或伪脱机发送到磁盘。这使得即使是巨大的文档也能被解析,而无需过多的资源需求。 |
---|---|
结构化内容 | 解析器实现应该能够在提取的内容中包含结构信息(标题,链接等)。客户端应用程序可以使用这些信息来更好地判断解析文档的不同部分的相关性。 |
输入元数据 | 客户端应用程序应该能够将文件名或声明的内容类型等元数据与要解析的文档包含在一起。解析器实现可以使用这些信息来更好地指导解析过程。 |
输出元数据 | 除文档内容之外,解析器实现应该能够返回文档元数据。许多文档格式都包含元数据,比如作者的名字,可能对客户端应用程序有用。 |
上下文敏感 | 尽管Tika解析器的默认设置和行为在大多数使用情况下都能很好地工作,但仍然存在需要对解析过程进行更精细化控制的情况。在不破坏抽象层的情况下,将这种特定于上下文的信息注入解析过程应该很容易。 |
要求
我们的前提条件如下:我们有一组存储在磁盘/数据库中的文档,我们希望为它们编制索引; 这些文档可以是Word文档,PDF文件,HTML文件,纯文本文件等等。由于我们是开发人员,我们希望编写可重复使用的代码来提取关于格式(元数据)的文件属性和文件内容。Apache Tika拥有一个mimetype存储库和一组方案(MIME MAGIC,URL模式,XML根字符或文件扩展名的任意组合)来确定特定文件,URL或内容是否与其中一种已知类型相匹配。如果内容确实匹配,Tika就检测它的mimetype并继续选择适当的解析器。
在示例代码中,类com.retriever.lucene.index.IndexCreator中的方法indexFile 覆盖了文件类型检测及其解析。
清单1.1用Tika分析文件
public static DocumentWithAbstract indexFile ( Analyzer analyzer , File file ) throws IOException {
Metadata metadata = new Metadata ( ) ;
ContentHandler handler = new BodyContentHandler ( 10 * 1024 * 1024 ) ;
ParseContext context = new ParseContext ( ) ;
Parser parser = new AutoDetectParser ( );
InputStream stream = new FileInputStream ( file ) ; //open stream
try {
parser . parse ( stream , handler , metadata , context ) ; //parse the stream
} catch ( TikaException e ) {
e . printStackTrace ( ) ;
} catch ( SAXException e ) {
e. printStackTrace ( ) ;
} finally {
stream . close ( ) ; //close the stream
}
//more code here
}
上面的代码显示了如何使用org.apache.tika.parser.AutoDetectParser解析文件;我们之所以选择这种实现方式,是因为我们希望在不考虑格式的情况下实现解析文档。另外,为了处理内容,org.apache.tika.sax.BodyContentHandler被构造为writeLimit参数(10 * 1024 * 1024); 这种类型的构造函数创建了一个内容处理程序,它将XHTML主体字符事件写入内部字符串缓冲区,以使在文档内容较大情况下抛出SAXException错误的可能性降到最低(在达到默认写入限制时抛出)。
作为解析的结果,我们获得了一个可以用来检测文件属性的元数据对象(标题或任何其他头部特定的其他文档格式)。元数据处理可以按照如下所述完成(com.retriever.lucene.index.IndexCreator,方法indexFileDescriptors):
清单1.2处理元数据
private static Document indexFileDescriptors(String fileName, Metadata metadata) {
Document doc = new Document();
//store file name in a separate TextField
doc.add(new TextField(ISearchConstants.FIELD_FILE, fileName, Store.YES));
for ( String key : metadata . names ( ) ) {
String name = key . toLowerCase ( ) ;
String value = metadata . get ( key ) ;
if ( StringUtils . isBlank ( value ) ) {
continue ;
}
if ( "keywords" . equalsIgnoreCase ( key ) ) {
for ( String keyword : value . split ( ",?(\\s+)" ) ) {
doc . add ( new TextField ( name , keyword , Store . YES ) ) ;
}
} else if ( ISearchConstants . FIELD_TITLE . equalsIgnoreCase (key ) ) {
doc . add ( new TextField ( name , value , Store . YES ) ) ;
} else {
doc . add ( new TextField ( name , fileName , Store . NO ) ) ;
}
}
在上面介绍的方法中,我们将文件名存储在单独的字段中,同时也存储文档的标题(文档可以有与其文件名不同的标题); 我们对储存其他信息没有兴趣。