注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Koala++'s blog

计算广告学 RTB

 
 
 

日志

 
 

企业级搜索引擎Solr 第三章 索引数据(Indexing Data)[3]  

2012-11-22 19:03:18|  分类: 搜索引擎 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

Indexing documents with Solr Cell

       虽然本书中假设你要建索引的内容都是有着良好结构的,比如数据库表,XML文件,CSV,但在现实中我们要保存很混乱的数据,或是二进制文件,如PDFMicrosoft Office,甚至是图片和音乐文件。

       我(Eric Pugh)在首次使用Solr时,就需要处理客户在几年间产生的大量PDFMicrosoft文档。随着Solr Cell的进步,和框架的支持,对富文档进行索引不再困难了。

       我们来看一个使用Solr CellMIDI文件中抽取卡拉OK歌词的例子。想想你可以建立你所喜欢的歌词的Solr索引,这是多令人激动呀。Solr Cell的完整参考资料在:http://wiki. apache.org/solr/ExtractingRequestHandler

Extracting text and metadata from files

       每个文件格式都不同,它们所提供的元数据类型也不同,当然抽取它们内容的方法也不同。Tika提供了单个API对所有格式进行处理,以减少复杂性。

       Tika支持多种数据格式。一些常用的格式都是支持的,比如Adobe PDFMicrosoft Office包括WordExcelPowerPointVisioOutlook。也支持从其它格式中抽取数据,如从JPGGIFPNG中抽取数据。还支持从多个音频中抽取数据如MP3MIDIWave audioTika它本并不解析这些文件格式。它只是一个代理,它调用多个第三方的库去解析,关于tika 0.8版的文档在http://tika. apache.org/0.8/formats.html

       Solr Cell是一个针对Tika的简单适配器,它由一个SAX ContentHandler组成,ContentHandler处理SAX事件,并通过指定要抽取的域产生文档。

       在索引二制进文件的时候,有些事要注意:

l  你可以提供任何Tika支持的文档类型给TikaTika会尝试确定文档正确的MIME类型,然后再调用相应的解析器。如果你已经知道了正确的MIME,你可以在stream.type参数中指定。

l  Solr Cell中默认的SolrContentHandler用起来很简单。你可能发现你不止需要Solr Cell提供的功能,你还需要对数据进行一些处理来减少垃圾数据被索引。其中一种实现的方法是自定义的Solr UpdateRequestProcessor,在本章后面会讲。另一种方式是实现子类ExtractingRequestHandlercreateFactory()来提供自定义的SolrContentHandler

l  请记住如果你可能会发送很大的二进制文件,然后由Solr解析,这样速度可能会很慢。如果你只想索引元数据,那你应该用Tika来编写自己的解析器来抽取元数据,再Post给服务器,见第九章。

你可以从Tika官网上学习到更多内容:http://tika.apache.org/

Configuring Solr

       /example/cores/karaoke/conf/solrconfig.xml文件中,有对二进制文档解析的请求处理器:

<requestHandler name="/update/extract"

class="org.apache.solr.handler.extraction.ExtractingRequestHandler">

<lst name="defaults">

<str name="map.Last-Modified">last_modified</str>

<str name="uprefix">metadata_</str>

</lst>

</requestHandler>

       这里我们可以看到Tika的元数据属性Last-Modified被映射到了Solr的域last_modified,参数uprefix是指定没有匹配对应Solr域名的域的名字的前缀。

       Solr Cell作为contrib模块发布,它包含大约25以上的JAR文件,它们每种能解析不同的文件格式。要使用Solr Cell,我们将Solr Cell Jar和其它的JAR放到karaoke核心中,/examples/cores/karaoke/lib,它默认不被引入solr.war,也不需要其它的核心的JAR。这些JAR文件放到lib,这时只有karaoke核心可以使用它。要将这些核心在多个核心中共享,你可以将它们加入到examples/cores/lib中,并在solr.xml中指定目录:

<solr persistent="false" sharedLib="lib">

       在这个例子中,我们用标准Javajavax.audio.midiMIDI格式的karaoke文件解析。如果你知道你所解析的文件格式是什么,你可以只加入你所需要的JAR文件,这可以让你的发布包更小,但是为了完备性,我们将所有依赖的JAR全部加入,比如pdfboxpoiicu4j./cores/karaoke/lib

Solr Cell parameters

       在进入示例之前,我们看一下Solr Cell的配置参数,所有参数都是可选的。

       首先,Solr Cell决定文档的格式。它通常会猜的比较准,但它也可以与下面的参数配合:

l  Resource.name:这个可选参数是指定文件的名字。它能帮助Tika来确定正确的MIME类型。

l  Stream.type:这个可选参数允许你明确地指定文档MIME类型,它会优先于Tika的猜测结果。

Tika将所有的输入文档软换为基础的XHTML文档,在头部分中包含元数据。元数据会成为域,内容的文档会映射到content域。下面的参数更详细:

l  CaptureX会被拷贝它自己的域中的HTML元素名称(比如:“p”),它可以被设置多次。

l  captureAttr:设置为true来获取XHTML属性到域中。一个常见的例子是用Tika抽取从<a/>抽取href属性来索引另一个域的索引。

l  xpath:允许你指定一个XPath查询,它不会将元素的文本放入content域。如果你只要得到元数据,丢弃XTHML中的正文,你可以用xpath=/xhtml:html/xhtml:head/descendant:node()。注意为每个元素使用xhtml:命名空间前缀。注意它支持一部分XPath命令。见http://tika.apache.org/0.8/api/org/apache/tika/sax/xpath/XPathParser.html。API中没有提到到它支持/descendant:node()

l  literal. [fieldname]:允许你为这个域一个特定的域值,比如,为ID域。

现在产生的域名都应该与Schema中的域名对应。下面是控制产生域名的参数:

l  lowernames:将域名都小写,并将非字母数字的字符都转换成下划线。比如Last-Updated变为last_updated

l  fmap.[tikaFieldName]:将源域名转换为目标域名。比如,fmap.last_modified=timestamp映射将由Tika产生元数据域的last_modified映射到Solr Schematimestamp域。

l  uprefix:这个前缀用于域名,如果没有加前缀的名字不匹配Schema中的域名。使用这个前缀可以与动态域中进行匹配:

uprefix=meta_

<dynamicField name="meta_*" type="text_general" indexed="true"

stored="true" multiValued="true"/>

l  defaultField:如果没有指定uprefix,并没有匹配Schema中的域名,那么域的值将写入这个参数指定的域名中。这样可以将所有元数据都入一个多值的域。

defaultField=meta

<field name="meta" type="text_general" indexed="true"

stored="true" multiValued="true"/>

       其它的一些参数:

l  boost. [fieldname]:由参数值对指定域进行Boost,来影响打分。

l  extractOnly:设置为true,仅返回Tika解析的XHTML的文档结档,而不进行建索引。通常还会带上参数wt=json&indent=true来使XHTML更容易读。这个选项用来帮助调试。

l  extractFormat(extractOnly=true)默认为xml,它产生XHMTL结构,可以设置为text产生从文档中抽取的原始文本。

Extracting karaoke lyrics

       现在我们可以将MIDI PostSolr /update/extract请求处理器来抽取卡拉OK的歌词。一些经典的ABBA音乐在./examples/3/karaoke/目录,是从FreeKaraoke中得到http://www.freekaraoke.com,在此感谢。

       要对Angel Eyes这首歌建索引,可以如下使用命令行:

>> curl 'http://localhost:8983/solr/karaoke/update/extract?fmap.content=text' -F "file=@angeleyes.kar"

       不要提交你的改变:

>> curl http://localhost:8983/solr/karaoke/update?commit=true

       你可以在发送一个文档的请求中加上commit=true请求参数进行提交,但是,在你建立大量文档时,这样做是低效的。

       我们只有一个fmap.conent=text参数来指定源中正文的文本都到text域。在这个例子中angeleyes.kar的歌词都保存到Solrtext域中。现在我们看一下索引结果:http:// localhost:8983/solr/karaoke/select/?q=*:*。你会看到下面结果:

<result name="response" numFound="1" start="0">

<doc>

<arr name="text">

<str>

Angel Eyes by Abba sequenced by Michael Boyce

tinker@worldnet.att.netSoft karaoke@KMIDI KARAOKE

FILEWords@LENGL@TAngel Eyes@TABBA\Last night I was taking

a walk along the river/And I saw him together with a young
girl/And the look that he gave made me shiver/'Cause

he always used ...

</str>

</arr>

</doc>

</result>

       你现在已经对MIDI文件中的歌词在text域中建立索引了。但是,元数据呢?Tika解析MIDI出的数据没有利用。嗯,这是动态域一展身手的地方了。每种二进制文件格式都有着很大的不同。幸运的是,Solr Cell通过使用uprefix属性让你来将元数据映射到动态域。我们在schema.xml中使用动态域:

<dynamicField name="metadata_*" type="string" indexed="true"

stored="true" multiValued="true"/>

       因为有时我们想标准化地处理元数据属性,我们可以在solrconfig.xml中加入下面的配置:

<str name="uprefix">metadata_</str>

       如果你提前知道一些元数据域的名字,并想进行域名映射,你可以配置:

<str name="fmap.content_type">content_type</str>

       当你搜索所有文档时,你应该可以看到Angel Eyes中所有的元数据,除了content_type外,其它都以metadata_为前缀。

<str name="content_type">audio/midi</str>

<arr name="metadata_patches"><str>0</str></arr>

<arr name="metadata_stream_content_type"><str>application/octetstream

</str></arr>

<arr name="metadata_stream_size"><str>55677</str></arr>

<arr name="metadata_stream_source_info"><str>file</str></arr>

<arr name="metadata_tracks"><str>16</str></arr>

       显然在大多情况下,你每次索引同一文件,你不想再产生一个新的Solr文档。如果在你的Schema中的uniqueKey域指定了如id的域,那你可以用literal.id=34参数提供一个特定的ID。每次你用相同的ID索引文件,它就会删除再插入这个文件。但是这就要求你要有管理ID的能力,可能需要第三方的支持,比如数据库。如果你想用元数据来做为ID,比如Tika提供的stream_name,那你可以用fmap.stream_name=id来映射域。要在这个例子中使用,更新./examples/cores/karaoke/schema.xml指定<uniqueKey>id</uniqueKey>

>> curl 'http://localhost:8983/solr/karaoke/update/extract?fmap.

content=text&fmap.stream_name=id' -F "file=@angeleyes.kar"

       这要求你所定义的id是字符串型,而不是数值型。

Indexing richer documents

       索引对MIDI文件中的卡拉OK歌词建索引是个微不足道的例子了。我们只简单的忽略了所有的内容,然后把它们存到Solrtext域中,不对文档的结构进行任何的处理。

       但是其它的文档结构,比如PDF,会更复杂,只是取得文本可能不会得到很好的搜索结果。我们看一下Take a Chance on Me,它是一个解释Monte Carlo模拟是什么的PDF文件。

       打开./examples/3/karaoke/mccm.pdf,你会看到一个复杂的PDF有很多字符,背景图片,复杂的数学公式,希腊字母,和图表。尽管这个PDF很复杂,索引它和索引卡拉OK文件一样简单:

>> curl 'http://localhost:8983/solr/karaoke/update/extract?map.

content=text&commit=true' -F "file=@mccm.pdf"

       如果你将文件名作为stream_name的参数进行搜索:http://localhost:8983/solr/karaoke/select/?q=stream_name:mccm.pdf,你会看到由Tika抽取出的Last_modified元数据被映射到solrconfig.xml中的last_modified域。

       其中设置的lowercase=true会将Last-Modified映射到last_modified,使它符合域名的规范。

<doc>

<arr name="id">

<str>mccm.pdf</str>

</arr>

<arr name="last_modified">

<str>Sun Mar 03 15:55:09 EST 2002</str>

</arr>

<arr name="text">

<str>

Take A Chance On Me

       那么对于富文档,我们将如何处理元数据和内容呢?在URL加入extractOnly=true,它会输出Solr Cell解析出的XML文档,包括元数据域,而不对文档建索引。

       追加wt=json会使它更容易解析出内嵌的XML内容:

>> curl 'http://localhost:8983/solr/karaoke/update/extract?extractOnly=tr

ue&wt=json&indent=true' -F "file=@mccm.pdf"

       复制粘贴JSON输出中内嵌的XML内容,用你最喜欢的HTML浏览工具查看内容。我用的是TextMateHTML插件,另一个不错的选择在http://xmlindent.com/

<html>

<head>

<meta name="stream_source_info" content="file">

<meta name="subject" content="Monte carlo condensed">

<meta name="Last-Modified" content="2002-03-03T20:55:09Z">

<meta name="Author" content="Andrew" n.=">

<meta name="xmpTPg:NPages" content="11">

<meta name="Creation-Date" content="2002-03-03T20:53:14Z">

<meta name="Keywords" content="ABBA">

<title>

Take A Chance On Me

</title>

</head>

<body>

<p>

"\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n

</p>

<div class="page">

\n\n

<p>

Take A Chance On MeMonte Carlo Condensed MatterA very brief

guide to Monte Carlo simulation.An explanation of what I do.A chance

for far too many ABBA puns.

</p>\n

</div>

<p>

\n

</p>

<div class="page">

\n\n

<p>

What's The Name Of The Game?Simulation:'I have a dream,

a fantasy,to help me through reality'Given some model many-body

system.Simulate the evolution of the system.We can then measure

various observables.Attempt to predict properties of real systems.

Eg Equilibrium Properties All about knowing free-energies, phase

behavior, compressibility, specific heat,knowing M(E), knowing m.

</p>\n

</div>

       返回的XHTML文档包含从文档在<head/>中的元数据,还有以XHTML格式表示的正文内容。

Update request processors

       无论你如何选择导入数据,都要在Solr中有一个最后一步的配置点,允许它在索引导入数据之前处理数据。Solr的请求处理器是将文档放到更新请求处理器链(update request processor chain)上进行数据更新。如果你在solrconfig.xml中查找updateRequestProcessorChain你会看到示例。

       它可以通过配置update.chain,选择哪个更新链来处理更新请求。它有一定用,但你可能只会用到一个链。如果没有链被指定,你会有一个默认的链,由LogUpdateProcessorFactoryRunUpdateProcessorFactory组成。下面是一些可以选择的更新请求处理器。它们名字都以UpdateProcessorFactory结尾。

l  SignatureUpdateProcessorFactory:它基于你指定的域产生一个Hash ID。如果你想对你的数据去重,那么这个会很适合你。更多的信息见:http://wiki.apache.org/solr/Deduplication

l  UIMAUpdateProcessorFactory:它将文档传给Unstructured Information Management ArchitectureUIMA),一个对文档进行自然语言处理的模块。更多信息见:http://wiki.apache.org/solr/SolrUIMA

l  LogUpdateProcessorFactory:它会在更新发生时记录Log信息。

l  RunUpdateProcessorFactory:它是真正建索引的部分,不要忘了它,否则文档更新不会有效果!更具体地说,它将文档传给Lucene,它会根据Schema中的配置对每个域进行处理。

未来会有很多的处理器来进行其它有趣的任务,包括一个类似DIHScriptTransformer的处理器,见SOLR-1725。你当然也可以写你自己的处理器。Solr对这点是支持扩展的,所以你不用改动Solr本身。

 

  评论这张
 
阅读(3567)| 评论(1)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017