企业级搜索引擎Solr 第三章 索引数据(Indexing Data)[1] (转)
Index Data
Author: David Smiley Eric Pugh
译者:Koala++ / 屈伟
在这一章中我们将了解如何将数据传入Solr。这个传入的过程称之为索引,尽管中间还包含了导入的过程。本章的结构如下:
l 与Solr交互。
l 以Solr的Update-XML格式发送数据。
l 提交,优化,回滚和删除。
l 以CSV 格式发送数据。
l 通过Solr的DataImportHandler直接读数据库和XML。
l 通过Solr的ExtractingRequestHandler从富文档中抽取数据。
l 用UpdateRequestProcessors进行文档后处理(post-processing)。
你会在第九章看到一些相关的内容,第九章中有语言绑定,框架集成,包括爬虫。大都用Solr的Update-XML格式。
Communicating With Solr
Solr提供了很多导入数据的方式。在本节中,我们将先介绍一些方法,给出一些交互的例子。一些特定格式,比如Solr的Update-XML的细节随后介绍。
Direct HTTP or a convenient client API
应用与Solr通过HTTP方式交互,你可以选择直接用你喜欢的HTTP客户端API,也可以使用与Solr集成的API,比如SolrJ或是Sunspot,它们将处理与HTTP交互的细节。这些API将在第九章介绍。HTTP Solr交互并不意味着需要索引的数据一定要通过HTTP传输,你马上会学习到如何告诉Solr去取数据。
Push data to Solr or have Solr pull it
尽管一个应用通过HTTP方式与Solr通信,并不意味着它需要将文档通过HTTP发送给Solr。Solr支持一种它称为remote streaming的方式,这种方式需要提供给它一个URL,它可以是一个HTTP URL,但一般它是一个基于文件系统的URL,基于文件系统的URL,可以在数据已经在Solr所在的本机或是在网络驱动中时可以使用。这种方式减少了HTTP方式的代价。另一种方式是让Solr通过DataImportHandler去拉取数据,这种方式可以从数据库和其它来源拉取数据。DIH提供了一个可扩展的框架,它可以扩展以适应自定义的数据源。
Data formats
下面是多种在Solr用来建索引的格式:
l Solr的Update-XML:Solr接受一种通过XML格式表达的Solr特定的格式。它也有删除,优化和提交的命令。
? 其它XML:任意的XML带上一个XSLT文件给Solr,Solr会将XML转化成Update-XML格式以进行后面的处理。
? Solr的Update-JSON:Solr的Update-XML的一个JavaScript Object Notation变形。更多细节见http://wiki.apache.org/solr/UpdateJSON。
? Java-Bin:Solr的Update-XML的一个高效的二进制变形。正式地只有SolrJ客户端API支持,但也有第三方的Ruby支持。
? CSV:逗号(或其它符号)分隔符的格式。
? 富文档:大多数常见的文件格式,比如PDF,XLS,DOC,PPT。文本和元数据都可以从这些格式中抽取出来,并放入Solr的域中。这可以通过Solr Cell Contrib模式完成。
我们将通过把MusicBrainz的数据以XML,CSV和数据库的方式导入Solr来展示Solr的能力。其它的例子将展示通过DIH将爬取的文件导入,和通过Solr Cell导入。但是通常来说一个应用只会用一种格式来导入。
在我们介绍这些方法之前,我们先介绍一下cURL和remote streaming,这两个是基本知识。
HTTP POSTing options to Solr
Solr通过HTTP POST接收命令,还可以接收文档数据。
发送HTTP POST的方法之一是使用UNIX命令行工具curl,我们将用它来介绍例子。另一个跨平台的工具是Solr中post.jar,它在Solr的example/exampledocs目录下。要得到一些使用信息,用下面的命令运行:
>> java –jar example/exampledocs/post.jar -help
有几种让Solr索引数据的方式,并所有的方式都是通过HTTP POST:
l 通过POST方式发送数据。curl的--data-binary参数可以做到这点,并会带一个与格式相符的content-type头。
l 发送一些类似一个HTML格式的键值对。Curl使用-F来进行。如果你不是在数据库中得到数据,你可以用下面的方式来进行:
? 将数据放在stream.body参数中。如果它比较小,也许小于1M,这种方式没有问题。大小的限制是在solrconfig.xml的multipartUpdateLimitInKB中,默认是2GB。如果你想提高限制,你应该再考虑一下你的方式。
? 用stream.file参数引用Solr服务器上的一个本地文件,或是通过stream.url参数通过一个URL去取数据。这些方式Solr称之为remote streaming。
下面是第一种选择的例子。我们假设有一个artists.xml在当前目录。我们可以用下面的命令Post这个文件。
>> curl http://localhost:8983/solr/mbartists/update -H 'Contenttype:text/xml; charset=utf-8' --data-binary @artists.xml
如果它成功了,你会得到下面的输出:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader">
<int name="status">0</int><int name="QTime">128</int>
</lst>
</response>
要用stream.body来完成上例,你可以写:
curl http://localhost:8983/solr/mbartists/update -F stream.body=@artists.xml
在两个例子中,@符号指示curl从文件中取得数据。如果XML比较短,你可以直接在命令行中写:
curl http://localhost:8983/solr/mbartists/update -F stream.body=' <commit/>'
注意在值中有一个空格,这是有意为之的。在本例中,curl对待@和<有特殊含义。在本例中应该用form-string而不是-F。但是我懒得打字了。
Remote streaming
在前面的例子中,我们通过HTTP方式将数据发给Solr建索引。另外,我们可以通过POST给Solr一个数据的位置让它去取数据,数据的位置可以是文件路径也可以是HTTP的URL。
像前面一样,如果Solr没有处理完请求,那么是不会返回响应的。如果文件大小合适或是它已经在某一已知的URL中了,那么你会发现remote streaming更快并且/或者更方便。
下面是一个Solr访问一个本地文件的例子:
curl http://localhost:8983/solr/mbartists/update -F stream.file=/tmp/artists.xml
如果要使用URL,那么参数就改为stream.url,并且将值指定为一个URL。我们现在传递的键值对参数,而不是真正的数据。
Solr's Update-XML format
你可以通过使用一个XML格式化的方式,来提供建索引的文档,告诉Solr提交改变,来优化索引,删除文档。下面是一个示例XML文件,你可以通过HTTP POST给Solr增加(或替换)两个文档:
<add overwrite="true">
<doc boost="2.0">
<field name="id">5432a</field>
<field name="type" ...</field>
<field name="a_name" boost="0.5"></field>
<!-- the date/time syntax MUST look just like this -->
<field name="begin_date">2007-12-31T09:40:00Z</field>
</doc>
<doc>
<field name="id">myid</field>
<field name="type" ...
<field name="begin_date">2007-12-31T09:40:00Z</field>
</doc>
<!-- more doc elements here as needed -->
</add>
其中overwirte属性默认为true保证你在schema中指定为unique的域的值唯一,如果你添加的另一个文档在unique的域中有相同的值,那么这个文档会替换前一个文档。你不会得到一个错误。
其中boost值会影响匹配文档时的得分。在文档或是域级别可选提供一个boost值。默认值是1.0,即无boost。技术上讲,不应该对文档进行boost,只应该对域进行boost。域最终的boost值是文档的boost值乘以域的boost值。
Deleting documents
你可以通过unique域删除一个文档。下面的例子是我们删除两个文档:
<delete><id>Artist:11604</id><id>Artist:11603</id></delete>
为更灵活地删除文档,你可以用Lucene/Solr查询删除文档:
<delete><query>timestamp:[* TO NOW-12HOUR]</query></delete>
内容中的delete标签可以有多个你想删除的id和query标签,这样一次可以批量删除多个文档。
查询语法会在第四章讨论。我简单解释上面的例子,我们假设我们的文档中有一个时间戳域,它是被索引的,并且你会每天进行一次数据全量重建。在一次全量数据更新后,就要删除以前的老数据。上面的查询会删除所有不在12小时以前建立索引的文档。12小时是随意选择一个值,但它需要小于24个小时并且大于加载所有数据的耗时。
Commit, optimize, and rollback
发送给Solr的数据不能立即搜索到,删除的文档也不会立即失效。像数据库一样,改动需要先提交(commit)。最简单的方式是在Solr的更新URL后加上commit=true请求参数。这个请求可以是包含更新数据的请求也可以是一个空的请求。比如,你可以通过访问URL产生一个提交到我们的mbreleases索引:http://localhost:8983/solr/mbreleases/update?commit=true。你也可以通过下面的XML语法提交,你只需要将它发送给Solr:
<commit />
你需要知道关于Solr提交的三个重要的点:
l 提交是缓慢的。速度依赖于索引的大小,Solr的auto-warming配置,和Solr的Cache状态的提交,一次提交会花费一些时间。通常,它需要几秒钟,但在极端情况下,它会花费几分钟。要了解如何减少提交时间,可以参考第十章。
l 没有事务隔离:这意味着如果多个Solr客户端提交修改,并且提交的时间重叠,那么就可能一个客户端的在发出提交命令之前,一部分修改已经提交了。这种情况也适用于回滚(rollback)。如果你的应用中存在这个问题,你应该考虑只使用一个客户端处理Solr的更新。
l 同时提交是可以避免的,特别是多个客户端的情况。这个问题其实属于同时query warming,query warming是影响提交时间的主要因素。如果有太多同时进行的warming Solr会使用大量的资源,甚至会产生一个错误,但是提交最后还是会正常提交。
如果你批量载入数据,在最后进行一次提交,这次提交你倒不用担心。但如果Solr由多个独立的客户端异步更新数据,提交可能很频繁也可能重复。为了解决这个问题,Solr有两个相似的特性,autoCommit和commitWithin。autoCommit是solrconfig.xml中一小段注释掉的配置,配置后Solr会在达到文档数阈值或是时间阈值(最老未提交文档的时间)后自动提交。这样,你的应用不用再发送提交,Solr会自己来处理提交。commitWithin是一个类似的时间阈值选项。这个选项可以由客户端提交的更新信息设置,信息是放到XML更新数据的<add commitWithin="…">元素或是<commit commitWithin="…"/>元素中,也可以通过设置请求的参数来设置。它会保证每隔多少毫秒进行一次提交。下面是30秒进行一次提交的例子:
<commit commitWithin="30000"/>
Lucene的索引内部是由一个或是多个Segments组成的。当索引文档的缓冲区写入磁盘时,它会创建一个新的Segment。删除信息是在另一个文件中,但它们也要写入文件。有时,当一个新Segment写入时,Lucene会将多个Segment合并。当Lucene只有一个Segment时,它处在已优化(optimized)状态。Segment个数越多,则查询的效率就越低下。当然,优化一个索引是需要代价的,你的索引越大,那么优化花费的时间就越长。最后优化命令的语法与提交是相同的。如果你想在URL中使用,你可以用http://localhost:8983/solr/mbreleases/update?optimize=true。对于XML格式,可以发送:
<optimize />
建议在比如批量载入数据时,并且/或是如果有零星的更新时,可以在一天内比较空闲的时间显式地进行索引优化。后面章节会介绍如果优化时间过长的情况下,对多个索引进行优化。
提交和优化都有两个布尔选项,它们默认设置为true:
<optimize waitFlush="true" waitSearcher="true"/>
如果你把它们设置为false,那么提交和优化命令会立即返回,即使操作并没有真正完成。所以如果你写一个脚本进行提交,并将上面两个选项设置为false,再进行查询。你会发现查询结果并没有反应出改变。通过等待数据入写磁盘(waitFlush)和等待新的索引可以反应数据改变(waitSearcher),则可以避免上述情况。
最后还有一个索引命令回滚(rollback)。它可以将未提交的改变回滚。Solr的回滚命令可以通过URL参数:http://localhost:8983/solr/mbreleases/update?rollback=true或是XML:
<rollback />
Sending CSV formatted data to Solr
如果你已经有一个CSV格式的数据或是对你来说得到CSV文件比XML或是JSON格式要容易,那么你可以选择CSV方式导入数据。Solr的CSV支持比较灵活。但你不能指定一个索引时的boost,但是它也不常用。
要得到MusicBrainz的Track数据,可以从一个本地的PostgreSQL数据中用下面命令导出数据:
psql -U postgres -d musicbrainz_db -c "COPY (\
select 'Track:' || t.id as id, 'Track' as type, t.name as t_name,
t.length/1000 as t_duration, a.id as t_a_id, a.name as t_a_name,
albumjoin.sequence as t_num, r.id as t_r_id, r.name as t_r_name, array_
to_string(r.attributes,' ') as t_r_attributes, albummeta.tracks as t_r_
tracks \
from (track t inner join albumjoin on t.id = albumjoin.track \
inner join album r on albumjoin.album = r.id left join albummeta on
albumjoin.album = albummeta.id) inner join artist a on t.artist = a.id \
) to '/tmp/mb_tracks.csv' CSV HEADER"
它大约会产生7百万行数据像下面一样的数据(前三行):
id,type,t_name,t_duration,t_a_id,t_a_name,t_num,t_r_id,t_r_name,t_r_
attributes,t_r_tracks
Track:183326,Track,In the Arms of Sleep,254,11650,The Smashing
Pumpkins,4,22471,Mellon Collie and the Infinite Sadness (disc 2: Twilight
to Starlight),0 1 100,14
Track:183328,Track,Tales of a Scorched Earth,228,11650,The Smashing
Pumpkins,6,22471,Mellon Collie and the Infinite Sadness (disc 2: Twilight
to Starlight),0 1 100,14
…
代码和CSV文件都在本书提供的补充资料中。要将CSV文件导入Solr,运行下面的命令:
curl http://localhost:8983/solr/update/csv -F f.t_r_attributes.split=true
-F f.t_r_attributes.separator=' ' -F overwrite=false -F commit=true -F
stream.file=/tmp/mb_tracks.csv
CSV选项通过-F来指定。
Configuration options
下面是对每个配置选项参数的解释。对于前面的MusicBrainz CSV文件例子,命令中只设置了多值域的分隔符t_r_attributes,并为了效率而禁用了唯一键(unique key)处理,其它的都采用默认值。
l separator:用于分隔域的分隔符。默认为逗号。
l header:如果设置为true,则文件的第一行是域名。
l fieldnames:如果第一行没有包含域名,那么你需要使用它来指定域名。用逗号分隔它们。如果某一列没有指定域名,这一列的值会被忽略。
l skip:指定不用导入的域。
l skipLines,指定要忽略输入文件中多少行。默认为0.
l trim:如果为true,则在最后一步移除域值开始和结尾的空格,即使是那些被引号引起来的空格。默认为false。Solr已经进行了初步的去空白字符了,但引号引起的空格不会被去除。
l encapsulator:这个符号是用于将一个域的值引起来,因为一个域中的值可能包括域分隔符,引起来后解析就不会错误地将域值解析成两个域值。它默认是双引号,除非它被转义了,比如:
11604, foo, "The ""second"" word is quoted.", bar
l escapse:如果输入文本中有这个字符,那么下一个字符就会被转义字符本身,即它不会被转义的字符不会被认为是特殊字符,比如:
11604, foo, The second\, word is followed by a comma., bar
l keepEmpty:指定是否空(0长度)域值是否应该被索引或是忽略。默认为false。
l overwirte:它是指是否有相同ID的文档是否应该覆盖另一个文档,ID是由Schema中指定的唯一键。它默认为true。如果你对确定你没有重复的ID,可以设置为false可以提高效率。
l split:它用于有多值的域的切分。指定多值间的分隔符。
l map:它可以将域值替换为另一个值,也可以移除某些域值。替换前和替换后的值用冒号分隔,你可以在MusicBrainz Track数据上用这一特性,你可将数值替换为一些更有意义的值。下面是一个例子:
-F keepEmpty=false -F f.t_r_attributes.map=0:
-F f.t_r_attributes.map=1:Album -F f.t_r_attributes.map=2:Single
这会使0被移除,因为它是无用的数据,几乎所有的Track都有这个值。我们将1映射为Album,2映射为Single。
企业级搜索引擎Solr 第三章 索引数据(Indexing Data)[1] (转)的更多相关文章
- 企业级搜索引擎Solr 第三章 索引数据(Indexing Data)[1]
转载:http://quweiprotoss.wap.blog.163.com/ Push data to Solr or have Solr pull it 尽管一个应用通过HTTP方式与Solr通 ...
- 企业级搜索引擎Solr 第三章 索引数据(Indexing Data)[3]
转载:http://quweiprotoss.wap.blog.163.com/ Solr Cell是一个针对Tika的简单适配器,它由一个SAX ContentHandler组成,ContentHa ...
- 企业级搜索引擎Solr 第三章 索引数据(Indexing Data)[2]--DIH
转载:http://quweiprotoss.wap.blog.163.com/w2/ DIH需要在solrconfig.xml中注册,如下: <requestHandler name=&quo ...
- 企业级搜索引擎Solr 第三章 索引数据(Indexing Data)
虽然本书中假设你要建索引的内容都是有着良好结构的,比如数据库表,XML文件,CSV,但在现实中我们要保存很混乱的数据,或是二进制文件,如PDF,Microsoft Office,甚至是图片和音乐文件. ...
- MVC5+EF6 简易版CMS(非接口) 第三章:数据存储和业务处理
目录 简易版CMS后台管理系统开发流程 MVC5+EF6 简易版CMS(非接口) 第一章:新建项目 MVC5+EF6 简易版CMS(非接口) 第二章:建数据模型 MVC5+EF6 简易版CMS(非接口 ...
- .Net程序员 Solr-5.3之旅 (三)Solr 从MSSQ导入索引数据
阅读目录 引言 准备工作 data-config.xml schema.xml 导入数据 结尾 附件下载 引言 Other men live to eat, while I eat to live.- ...
- 企业级搜索引擎Solr使用入门指南
由于搜索引擎功能在门户社区中对提高用户体验有着重在门户社区中涉及大量需要搜索引擎的功能需求,目前在实现搜索引擎的方案上有集中方案可供选择: 基于Lucene自己进行封装实现站内搜索. 工作量及扩展性都 ...
- 【solr】SolrCloud中索引数据存储于HDFS
SolrCloud中索引数据存储于HDFS 本人最近使用SolrCloud存储索引日志条件,便于快速索引,因为我的索引条件较多,每天日志记录较大,索引想到将日志存入到HDFS中,下面就说说怎么讲sol ...
- C#高级编程第11版 - 第三章 索引
[1]3.1 创建及使用类 1.构造函数:构造函数的名字与类名相同: 使用 new 表达式创建类的对象或者结构(例如int)时,会调用其构造函数.并且通常初始化新对象的数据成员. 除非类是静态的,否则 ...
随机推荐
- 循序渐进学.Net Core Web Api开发系列【14】:异常处理
系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇介绍异 ...
- Oracle的一些初步小东西
经常要用数据库,让他自己启动的话,开机太慢,所以用命令启动方便点. 1.开启: 在运行中输入cmd,进入控制台,lsnrctl start回车,提示启动监听成功后net start Oracl ...
- C#开发Unity游戏教程循环遍历做出判断及Unity游戏示例
C#开发Unity游戏教程循环遍历做出判断及Unity游戏示例 Unity中循环遍历每个数据,并做出判断 很多时候,游戏在玩家做出判断以后,游戏程序会遍历玩家身上大量的所需数据,然后做出判断,即首先判 ...
- ehcache 在web项目中使用
无论是servlet web项目还是spring web项目,使用ehcache添加3个jre包以及配置 ehcache.xml即可.
- Gym 100646 Problem C: LCR 模拟题
Problem C: LCR 题目连接: http://codeforces.com/gym/100646/attachments Description LCR is a simple game f ...
- Kruskal 模板
最小生成树指的是在图上面找到权值最小的一棵树,并且保证图上所有的点都在这棵树上. 解决办法:Kruskal 算法(贪心思想) 将边按权值从小到大排序,然后按这个顺序不断连边,直到所有点联通. /** ...
- MikroTik RouterOS电子克隆盘原理收集
终于搞定RouteROS8位电子盘克隆,发个讯息出来分享一下. 不需要付费的免费分享,也没要刻意挡人财路:只是让信息流通一下. 也请看到的人不要用这个方式去赚钱,不然MikroTik还是会再反制的. ...
- MikroTik RouterOS 5.x使用HunterTik 2.3.1进行破解
一.加载光驱: 二.一路回车: 三.说明: 1.可以不安装Debian内核,但如果在无缝升级到6.6的版本,此项就一定要选择. 2.6版本的破解必须小于等于1G的空间,不然无法破解成功,亲测有效,如果 ...
- 关于Android中传递数据的一些讨论
在Android中编写过程序的开发人员都知道.在Activity.Service等组件之间传递数据(尤其是复杂类型的数据)很不方便.一般可以使用Intent来传递可序列化或简单类型的数据.看下面的代码 ...
- python及扩展程序安装
安装 从官方网站下载python程序,我下载的是python-3.3.2.msi 然后下载python扩展程序,我下载的是pywin32-218.win32-py3.3.exe 最后下载wmi插件,我 ...