前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >通过使用Apache Lucene和Tika了解信息检索 - 第1部分

通过使用Apache Lucene和Tika了解信息检索 - 第1部分

作者头像
mumuumum
发布2018-06-01 10:44:19
2.2K0
发布2018-06-01 10:44:19

介绍

在本教程中,将通过它们的核心概念(例如语法解析,MIME检测,内容分析法,索引,scoring方法,boosting方法)来解释Apache Lucene和Apache Tika框架,这些示例不仅适用于经验丰富的软件开发人员,还适用于内容分析法和编程的初学者。我们假设您具备Java™编程语言应用知识和大量可供分析的内容。

在本教程中,您将学习:

  • 如何使用Apache Tika的API及其最相关的功能
  • 如何使用Apache Lucene API及其最重要的模块开发代码
  • 如何整合Apache Lucene和Apache Tika,以构建自己的一款能有效存储和检索信息的软件。(项目代码可供下载)

什么是Lucene和Tika?

根据Apache Lucene的网站,Apache Lucene代表了一个开源的Java库,可被用于从大量文档集合中进行索引和搜索。索引大小约占索引文本大小的20-30%,搜索算法提供的功能如下:

  • 排名搜索 - 最好的结果优先返回
  • 许多强大的查询类型:短语查询,通配符查询,邻近查询,范围查询等等。在本教程中,我们将仅演示短语查询。
  • 部署搜索(例如标题,作者,内容)
  • 按任何字段排序
  • 灵活的切面,高亮显示,连接和结果分组
  • 可插入排序模型,包括Vector Space ModelOkapi BM25

但是Lucene的主要目的是直接处理文本,和我们想操作的具有各种格式和编码的文档。为了解析文档内容及其属性,Apache Tika库是必要的。

Apache Tika是一个库,它提供了一组灵活和强大的接口,可用于任何需要元数据分析和结构化文本提取的环境中。Apache Tika的关键组件是Parser(org.apache.tika.parser.Parser)接口,因为它隐藏了不同文件格式的复杂性,同时提供了一种简单而强大的机制来从各种文档中提取结构化文本内容和元数据。

Tika解析设计的标准

流式解析

该接口既不需要客户端应用程序也不需要解析器实现来将完整的文档内容保存在内存中或伪脱机发送到磁盘。这使得即使是巨大的文档也能被解析,而无需过多的资源需求。

结构化内容

解析器实现应该能够在提取的内容中包含结构信息(标题,链接等)。客户端应用程序可以使用这些信息来更好地判断解析文档的不同部分的相关性。

输入元数据

客户端应用程序应该能够将文件名或声明的内容类型等元数据与要解析的文档包含在一起。解析器实现可以使用这些信息来更好地指导解析过程。

输出元数据

除文档内容之外,解析器实现应该能够返回文档元数据。许多文档格式都包含元数据,比如作者的名字,可能对客户端应用程序有用。

上下文敏感

尽管Tika解析器的默认设置和行为在大多数使用情况下都能很好地工作,但仍然存在需要对解析过程进行更精细化控制的情况。在不破坏抽象层的情况下,将这种特定于上下文的信息注入解析过程应该很容易。

要求

  • Maven 2.0或更高版本
  • Java 1.6 SE或更高版本

第1课:从任何文件类型自动提取元数据

我们的前提条件如下:我们有一组存储在磁盘/数据库中的文档,我们希望为它们编制索引; 这些文档可以是Word文档,PDF文件,HTML文件,纯文本文件等等。由于我们是开发人员,我们希望编写可重复使用的代码来提取关于格式(元数据)的文件属性和文件内容。Apache Tika拥有一个mimetype存储库和一组方案(MIME MAGIC,URL模式,XML根字符或文件扩展名的任意组合)来确定特定文件,URL或内容是否与其中一种已知类型相匹配。如果内容确实匹配,Tika就检测它的mimetype并继续选择适当的解析器。

在示例代码中,类com.retriever.lucene.index.IndexCreator中的方法indexFile 覆盖了文件类型检测及其解析。

清单1.1用Tika分析文件

代码语言:javascript
复制
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处理元数据

代码语言:javascript
复制
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 ) ) ; 
            } 
        }

在上面介绍的方法中,我们将文件名存储在单独的字段中,同时也存储文档的标题(文档可以有与其文件名不同的标题); 我们对储存其他信息没有兴趣。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 介绍
    • 什么是Lucene和Tika?
    • 第1课:从任何文件类型自动提取元数据
    相关产品与服务
    大数据
    全栈大数据产品,面向海量数据场景,帮助您 “智理无数,心中有数”!
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档