http://blog.csdn.net/xzknet/article/details/6710753
?
以下資料整理自網(wǎng)絡(luò),覺的有必要合并在一起,這樣方便查看。主要分為兩部分,第一部分是對(duì)《db-data-config.xml》的配置內(nèi)容的講 解(屬于高級(jí)內(nèi)容),第二部分是DataImportHandler(屬于基礎(chǔ)),第三部分是對(duì)db-data-config.xml的進(jìn)階(這個(gè)國內(nèi)可 能還沒有人寫過啊,我在google、baidu上都沒有搜索到,最后可是拔代碼,看solr的英文文檔找的)
第一部分是對(duì)《db-data-config.xml》
query是獲取全部數(shù)據(jù)的SQL
deltaImportQuery是獲取增量數(shù)據(jù)時(shí)使用的SQL
deltaQuery是獲取pk的SQL
parentDeltaQuery是獲取父Entity的pk的SQL
Full Import工作原理
:
執(zhí)行本Entity的Query,獲取所有數(shù)據(jù);
針對(duì)每個(gè)行數(shù)據(jù)Row,獲取pk,組裝子Entity的Query;
執(zhí)行子Entity的Query,獲取子Entity的數(shù)據(jù)。
Delta Import工作原理
:
查找子Entity,直到?jīng)]有為止;
執(zhí)行Entity的deltaQuery,獲取變化數(shù)據(jù)的pk;
合并子Entity parentDeltaQuery得到的pk;
針對(duì)每一個(gè)pk Row,組裝父Entity的parentDeltaQuery;
執(zhí)行parentDeltaQuery,獲取父Entity的pk;
執(zhí)行deltaImportQuery,獲取自身的數(shù)據(jù);
如果沒有deltaImportQuery,就組裝Query
限制
:
子Entity的query必須引用父Entity的pk
子Entity的parentDeltaQuery必須引用自己的pk
子Entity的parentDeltaQuery必須返回父Entity的pk
deltaImportQuery引用的必須是自己的pk
第二部分是DataImportHandler
關(guān)于DataImportHandler的具體使用方法,詳見下文,如果你英文超級(jí)好,那看這個(gè)鏈接吧:http://wiki.apache.org/solr/DataImportHandler
??大多數(shù)的應(yīng)用程序?qū)?shù)據(jù)存儲(chǔ)在關(guān)系數(shù)據(jù)庫、xml文件中。對(duì)這樣的數(shù)據(jù)進(jìn)行搜索是很常見的應(yīng)用。所謂的DataImportHandler提供一種可配置的方式向solr導(dǎo)入數(shù)據(jù),可以一次全部導(dǎo)入,也可以增量導(dǎo)入。
????? 概覽
???????? 目 標(biāo)
- ?????能夠讀取關(guān)系數(shù)據(jù)庫中的數(shù)據(jù)。
- ?????通過可配置的方式,能夠?qū)?shù)據(jù)庫中多列、多表的數(shù)據(jù)生成solr文檔??
- ?????能夠通過solr文檔更新solr
- ???? 提供 通過配置文件就能夠?qū)胨袛?shù)據(jù)的能力
- ????? 能夠發(fā)現(xiàn)并處理 由insert、update帶來的變化(我們假定在表中有一個(gè)叫做“l(fā)ast-modified的列”)
- ??????能夠配置 “完全導(dǎo)入”和“增量導(dǎo)入”的時(shí)間
- ????? 讓讀取xml文件,并建立索引成為可配置。
- ????? 能夠?qū)?其他的數(shù)據(jù)源(例如:ftp,scp,etc)或者其他格式的文檔(Json,csv)以插件的形式集成到項(xiàng)目中。
???????? ? 設(shè)計(jì)思路
????????? ? 這個(gè)Handler首先要在solrconfig.xml文件中配置下,如下所示。
??????????????????<requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler">
??? <lst name="defaults">
????? <str name="config">/home/username/data-config.xml</str>?????
??? </lst>
? </requestHandler>
從它的名字上,我們或許也可以猜到, DataImportHandler正是requestHandler的實(shí)現(xiàn)。我們一共需要在兩個(gè)地方配置文件中進(jìn)行一些配置。
- solrconfig.xml?。 data-config.xml必須在這個(gè)文件中配置,datasource也可以。不過,一般將datasource放在data-config.xml文件中。
- data-config.xml
-
?
- ???怎樣獲取數(shù)據(jù)?(查詢語句、url等等)
- ? 要讀什么樣的數(shù)據(jù)(關(guān)系數(shù)據(jù)庫中的列、或者xml的域)
- ?? 做什么樣的處理(修改/添加/刪除)
??? ???跟關(guān)系數(shù)據(jù)庫一起使用
????????????? 下面幾個(gè)步驟是必要的.
- ?????定義一個(gè)data-config.xml 文件,并這個(gè)它的路徑配置到solrconfig.xml 中關(guān)于DataImportHandler的配置中。
- ????? 給出Connection的信息(假設(shè)你選擇在solrconfig中配置datasource)
- 打開DataImportHandler頁面去驗(yàn)證,是否該配置的都配置好了。 http://localhost:8983/solr/dataimport
- 使用“完全導(dǎo)入”命令將數(shù)據(jù)從數(shù)據(jù)庫中導(dǎo)出,并提交給solr建立索引
- 使用“增量導(dǎo)入”命令對(duì)數(shù)據(jù)庫發(fā)生的變化的數(shù)據(jù)導(dǎo)出,并提交給solr建立索引。
?????????? 配置數(shù)據(jù)源
??????? 將dataSource標(biāo)簽直接添加到dataConfig下面,即成為dataConfig的子元素.
<dataSource type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost/dbname" user="db_username" password="db_password"/>
- ????? 數(shù)據(jù)源也可以配置在solrconfig.xml中
- 屬性type 指定了實(shí)現(xiàn)的類型。它是可選的。默認(rèn)的實(shí)現(xiàn)是JdbcDataSource。
- 屬性 name? 是datasources的名字,當(dāng)有多個(gè)datasources時(shí),可以使用name屬性加以區(qū)分
- 其他的屬性都是隨意的,根據(jù)你使用的DataSource實(shí)現(xiàn)而定。
- 當(dāng)然 你也可以實(shí)現(xiàn)自己的DataSource。
????????? 多數(shù)據(jù) 源
?????一個(gè)配置文件可以配置多個(gè)數(shù)據(jù)源。增加一個(gè)dataSource元素就可以增加一個(gè)數(shù)據(jù)源了。name屬性可以區(qū)分不同的數(shù)據(jù)源。如果配置了多于一個(gè)的數(shù)據(jù)源,那么要注意將name配置成唯一的。
???例如:
<dataSource type="JdbcDataSource" name="ds-1" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://db1-host/dbname" user="db_username" password="db_password"/> <dataSource type="JdbcDataSource" name="ds-2" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://db2-host/dbname" user="db_username" password="db_password"/>
然后這樣使用
.. <entity name="one" dataSource="ds-1" ...> .. </entity> <entity name="two" dataSource="ds-2" ...> .. </entity> ..
配置JdbcDataSource
JdbcDataSource中的屬性有
- driver(必需的):jdbc驅(qū)動(dòng)名稱
- url(必需的):jdbc鏈接
- user:用戶名
- password:密碼
- 批量大小:jdbc鏈接中的批量大小
任何其他的在JdbcDataSource中配置的屬性,都會(huì)被直接傳給jdbc driver
配置data-config.xml
?? solr document是schema,它的域上的值可能來自于多個(gè)表.
???data- config.xml的根元素是document。一個(gè)document元素代表了一種文檔。一個(gè)document元素中包含了一個(gè)或者多個(gè)root實(shí) 體。一個(gè)root實(shí)體包含著一些子實(shí)體,這些子實(shí)體能夠包含其他的實(shí)體。實(shí)體就是,關(guān)系數(shù)據(jù)庫上的表或者視圖。每個(gè)實(shí)體都能夠包含多個(gè)域,每個(gè)域?qū)?yīng)著數(shù) 據(jù)庫返回結(jié)果中的一列。域的名字跟列的名字默認(rèn)是一樣的。如果一個(gè)列的名字跟solr field的名字不一樣,那么屬性name就應(yīng)該要給出。其他的需要的屬性在solrschema.xml文件中配置。
??? 為了能夠從數(shù)據(jù)庫中取得想要的數(shù)據(jù),我們的設(shè)計(jì)支持標(biāo)準(zhǔn)sql規(guī)范。這使得用戶能夠使用他任何想要的sql語句。root實(shí)體是一個(gè)中心表,使用它的列可以把表連接在一起。
???? dataconfig的結(jié)構(gòu)
??? dataconfig的結(jié)構(gòu)不是一成不變的,entity和field元素中的屬性是隨意的,這主要取決于processor和transformer。
????? 以下是entity的默認(rèn)屬性
- ?name(必需的):name是唯一的,用以標(biāo)識(shí)entity
- processor:只有當(dāng)datasource不是RDBMS時(shí)才是必需的。默認(rèn)值是 SqlEntityProcessor
- transformer:轉(zhuǎn)換器將會(huì)被應(yīng)用到這個(gè)entity上,詳情請(qǐng)瀏覽transformer部分。
- pk:entity的主鍵,它是可選的,但使用“增量導(dǎo)入”的時(shí)候是必需。它跟schema.xml中定義的uniqueKey沒有必然的聯(lián)系,但它們可以相同。
- rootEntity:默認(rèn)情況下,document元素下就是根實(shí)體了,如果沒有根實(shí)體的話,直接在實(shí)體下面的實(shí)體將會(huì)被看做跟實(shí)體。對(duì)于根實(shí)體對(duì)應(yīng)的數(shù)據(jù)庫中返回的數(shù)據(jù)的每一行,solr都將生成一個(gè)document。
???? 一下是SqlEntityProcessor的屬性
-
query (required) :sql語句
-
deltaQuery : 只在“增量導(dǎo)入”中使用
-
parentDeltaQuery : 只在“增量導(dǎo)入”中使用
-
deletedPkQuery : 只在“增量導(dǎo)入”中使用
-
deltaImportQuery : (只在“增量導(dǎo)入”中使用) . 如果這個(gè)存在,那么它將會(huì)在“增量導(dǎo)入”中導(dǎo)入phase時(shí)代替query產(chǎn)生作用。這里有一個(gè)命名空間的用法 ${dataimporter.delta.} 詳情請(qǐng)看solr1.4.
Commands
The handler 通過httprequest 向外界提供它的API?.?以下是一些或許你會(huì)用到的操作
-
full-import :?"完全導(dǎo)入"這個(gè)操作可以通過訪問URL http://:/solr/dataimport?command=full-import 完成。
-
這個(gè)操作,將會(huì)新起一個(gè)線程。response中的attribute屬性將會(huì)顯示busy。
-
這個(gè)操作執(zhí)行的時(shí)間取決于數(shù)據(jù)集的大小。
-
當(dāng)這個(gè)操作運(yùn)行完了以后,它將在conf/dataimport.properties這個(gè)文件中記錄下這個(gè)操作的開始時(shí)間
-
當(dāng)“增量導(dǎo)入”被執(zhí)行時(shí),stored timestamp這個(gè)時(shí)間戳將會(huì)被用到
-
solr的查詢?cè)凇巴耆珜?dǎo)入”時(shí),不是阻塞的
-
它還有下面一些參數(shù):
-
clean : (default 'true'). 決定在建立索引之前,刪除以前的索引。
-
commit : (default 'true'). 決定這個(gè)操作之后是否要commit
-
optimize : (default 'true').?決定這個(gè)操作之后是否要優(yōu)化。
-
debug : (default false). 工作在debug模式下。詳情請(qǐng)看 the interactive development mode ( see here )
-
-
-
delta-import : 當(dāng)遇到一些增量的輸入,或者發(fā)生一些變化時(shí)使用`
http:// :/solr/dataimport?command=delta-import .?它同樣支持? clean, commit, optimize and debug 這幾個(gè)參數(shù).
-
status :?想要知道命令執(zhí)行的狀態(tài) ,?訪問 URL http://:/solr/dataimport .它給出了關(guān)于文檔創(chuàng)建、刪除,查詢、結(jié)果獲取等等的詳細(xì)狀況。
-
reload-config : 如果data-config.xml已經(jīng)改變,你不希望重啟solr,而要重新加載配置時(shí),運(yùn)行一下的命令http://:/solr/dataimport?command=reload-config
-
abort :?你可以通過訪問 url http://:/solr/dataimport?command=abort 來終止一個(gè)在運(yùn)行的操作
Full Import 例子
讓我們來看下面的例子. 假設(shè)我們數(shù)據(jù)庫中的表結(jié)構(gòu)如下:
This is a relational model of the same schema that Solr currently ships with. 我們使用這個(gè)例子來為我們的DataImportHandler建data-config.xml。 我們已經(jīng)使用這個(gè)結(jié)構(gòu)在HSQLDB上建立了一個(gè)數(shù)據(jù)庫. 好,現(xiàn)在開始了, 跟著下面的步驟走:?
-
下載? example-solr-home.jar ?并使用 jar解壓 ? jar -xvf example-solr-home.jar ,解壓到你的本地系統(tǒng). 這個(gè)jar文件包含了一個(gè)完整的solrhome(里面的配置文件很齊全了)和一個(gè)RSS的例子。它也包含了一個(gè)hssqldb數(shù)據(jù)庫的例子.
-
在?example-solr-home目錄, 這里有一個(gè) solr.war . 拷貝?這個(gè) war 文件到你的 tomcat/jetty webapps 文件夾.? 這個(gè) war file 也包含了hsqldb的JDBC driver.?如果你想在你已經(jīng)有了的solr項(xiàng)目中部署,你只需要將? 'dataimport.jar'?拷貝到?你的solr項(xiàng)目的 WEB-INF/lib 目錄下。
-
使用example-data-config目錄下的solr目錄作為你solrhome
-
訪問?
http://localhost:8983/solr/dataimport 驗(yàn)證一下配置
-
訪問?
http://localhost:8983/solr/dataimport?command=full-import 執(zhí)行一個(gè)“完全導(dǎo)入”
上面給出的solr目錄是一個(gè)多核的solr home。它有兩個(gè)核,一個(gè)是DB example,一個(gè)是RSSexample(新屬性)。
這個(gè)例子的data-config.xml 如下:
<dataConfig> <dataSource driver="org.hsqldb.jdbcDriver" url="jdbc:hsqldb:/temp/example/ex" user="sa" /> <document name="products"> <entity name="item" query="select * from item"> <field column="ID" name="id" /> <field column="NAME" name="name" /> <field column="MANU" name="manu" /> <field column="WEIGHT" name="weight" /> <field column="PRICE" name="price" /> <field column="POPULARITY" name="popularity" /> <field column="INSTOCK" name="inStock" /> <field column="INCLUDES" name="includes" /> <entity name="feature" query="select description from feature where item_id='${item.ID}'"> <field name="features" column="description" /> </entity> <entity name="item_category" query="select CATEGORY_ID from item_category where item_id='${item.ID}'"> <entity name="category" query="select description from category where id = '${item_category.CATEGORY_ID}'"> <field column="description" name="cat" /> </entity> </entity> </entity> </document> </dataConfig>
這里, 根實(shí)體是一個(gè)名叫“item”的表,它的主鍵是id。我們使用語句 "select * from item"讀取數(shù)據(jù). 每一項(xiàng)都擁有多個(gè)特性。看下面feature實(shí)體的查詢語句
<entity name="feature" query="select description from feature where item_id='${item.id}'"> <field name="feature" column="description" /> </entity>
feature表中的外鍵item_id跟item中的主鍵連在一起從數(shù)據(jù)庫中取得該row的數(shù)據(jù)。相同地,我們將item和category連表(它們是多對(duì)多的關(guān)系)。注意,我們是怎樣使用中間表和標(biāo)準(zhǔn)sql連表的
?<entity name="item_category" query="select category_id from item_category where item_id='${item.id}'">
??????????????? <entity name="category" query="select description from category where id = '${item_category.category_id}'">
??????????????????? <field column="description" name="cat" />
??????????????? </entity>
??????????? </entity>
短一點(diǎn)的?data-config
在上面的例子中,這里有好幾個(gè)從域到solr域之間的映射。如果域的名字和solr中域的名字是一樣的話,完全避免使用在實(shí)體中配置域也是可以的。當(dāng)然,如果你需要使用轉(zhuǎn)換器的話,你還是需要加上域?qū)嶓w的。
下面是一個(gè)更短的版本
<dataConfig> <dataSource driver="org.hsqldb.jdbcDriver" url="jdbc:hsqldb:/temp/example/ex" user="sa" /> <document> <entity name="item" query="select * from item"> <entity name="feature" query="select description as features from feature where item_id='${item.ID}'"/> <entity name="item_category" query="select CATEGORY_ID from item_category where item_id='${item.ID}'"> <entity name="category" query="select description as cat from category where id = '${item_category.CATEGORY_ID}'"/> </entity> </entity> </document> </dataConfig>
使用“增量導(dǎo)入”命令
你可以通過訪問URL
http://localhost:8983/solr/dataimport?command=delta-import
?來使用增量導(dǎo)入。操作將會(huì)新起一個(gè)線程,response中的屬性statue也將顯示busy now。操作執(zhí)行的時(shí)間取決于你的數(shù)據(jù)集的大小。在任何時(shí)候,你都可以通過訪問??
http://localhost:8983/solr/dataimport
來查看狀態(tài)。
當(dāng) 增量導(dǎo)入被執(zhí)行的時(shí)候,它讀取存儲(chǔ)在conf/dataimport.properties中的“start time”。它使用這個(gè)時(shí)間戳來執(zhí)行增量查詢,完成之后,會(huì)更新這個(gè)放在conf/dataimport.properties中的時(shí)間戳。
Delta-Import 例子
我們將使用跟“完全導(dǎo)入”中相同的數(shù)據(jù)庫。注意,數(shù)據(jù)庫已經(jīng)被更新了,每個(gè)表都包含有一個(gè)額外timestamp類型的列? 叫做last_modified。或許你需要重新下載數(shù)據(jù)庫,因?yàn)樗罱桓铝恕N覀兪褂眠@個(gè)時(shí)間戳的域來區(qū)別出那一行是上次索引以來有更新的。
看看下面的這個(gè)?data-config.xml
<dataConfig> <dataSource driver="org.hsqldb.jdbcDriver" url="jdbc:hsqldb:/temp/example/ex" user="sa" /> <document name="products"> <entity name="item" pk="ID" query="select * from item" deltaQuery="select id from item where last_modified > '${dataimporter.last_index_time}'"> <entity name="feature" pk="ITEM_ID" query="select description as features from feature where item_id='${item.ID}'"> </entity> <entity name="item_category" pk="ITEM_ID, CATEGORY_ID" query="select CATEGORY_ID from item_category where ITEM_ID='${item.ID}'"> <entity name="category" pk="ID" query="select description as cat from category where id = '${item_category.CATEGORY_ID}'"> </entity> </entity> </entity> </document> </dataConfig>
注意到item實(shí)體的 屬性deltaquery了嗎,它包含了一個(gè)能夠查出最近更新的sql語句。注意,變量 {dataimporter.last_index_time } 是DataImporthandler傳過來的變量,我們叫它時(shí)間戳,它指出“完全導(dǎo)入”或者“部分導(dǎo)入”的最后運(yùn)行時(shí)間。你可以在data-config.xml文件中的sql的任何地方使用這個(gè)變量,它將在processing這個(gè)過程中被賦值。
?注意
-
上面例子中deltaQuery 只能夠發(fā)現(xiàn)item中的更新,而不能發(fā)現(xiàn)其他表的。你可以像下面那樣在一個(gè)sql語句中指定所有的表的更新。這里要特別說明一下的就是,它的細(xì)節(jié)對(duì)于一個(gè)使用者來說是一個(gè)不錯(cuò)的練習(xí)。
deltaQuery="select id from item where id in (select item_id as id from feature where last_modified > '${dataimporter.last_index_time}') or id in (select item_id as id from item_category where item_id in (select id as item_id from category where last_modified > '${dataimporter.last_index_time}') or last_modified > '${dataimporter.last_index_time}') or last_modified > '${dataimporter.last_index_time}'"
-
寫一個(gè)類似上面的龐大的deltaQuery 并不是一件很享受的工作,我們還是選擇其他的方法來達(dá)到這個(gè)目的
?
<dataConfig> <dataSource driver="org.hsqldb.jdbcDriver" url="jdbc:hsqldb:/temp/example/ex" user="sa" /> <document> <entity name="item" pk="ID" query="select * from item" deltaQuery="select id from item where last_modified > '${dataimporter.last_index_time}'"> <entity name="feature" pk="ITEM_ID" query="select DESCRIPTION as features from FEATURE where ITEM_ID='${item.ID}'" deltaQuery="select ITEM_ID from FEATURE where last_modified > '${dataimporter.last_index_time}'" parentDeltaQuery="select ID from item where ID=${feature.ITEM_ID}"/> <entity name="item_category" pk="ITEM_ID, CATEGORY_ID" query="select CATEGORY_ID from item_category where ITEM_ID='${item.ID}'" deltaQuery="select ITEM_ID, CATEGORY_ID from item_category where last_modified > '${dataimporter.last_index_time}'" parentDeltaQuery="select ID from item where ID=${item_category.ITEM_ID}"> <entity name="category" pk="ID" query="select DESCRIPTION as cat from category where ID = '${item_category.CATEGORY_ID}'" deltaQuery="select ID from category where last_modified > '${dataimporter.last_index_time}'" parentDeltaQuery="select ITEM_ID, CATEGORY_ID from item_category where CATEGORY_ID=${category.ID}"/> </entity> </entity> </document> </dataConfig>
除了根實(shí)體(有兩個(gè))以外,這里一共有三個(gè)查詢,每個(gè)實(shí)體個(gè)一個(gè)。
查詢語句,為我們?nèi)〉眯枰⑺饕臄?shù)據(jù)。
-
deltaQuery 取得從上次索引更新時(shí)間以來有更新的實(shí)體的主鍵。
-
parentDeltaQuery 從deltaQuery中取得當(dāng)前表中更新的行,并把這些行提交給父表。因?yàn)椋?dāng)子表中的一行發(fā)生改變時(shí),我們需要更新它的父表的solr文檔。
下面是一些值得注意的地方:
-
對(duì)于query語句返回的每一行,子實(shí)體的query都將被執(zhí)行一次
-
對(duì)于deltaQuery返回的每一行,parentDeltaQuery都將被執(zhí)行。
-
一旦根實(shí)體或者子實(shí)體中的行發(fā)生改變,我們將重新生成包含該行的solr文檔。
?XML/HTTP Datasource使用指南
DataImportHandler 能夠幫我們?yōu)榛贖TTP的數(shù)據(jù)源建立索引. 目前支持REST/XML APIs 和RSS/ATOM Feeds.
配置HttpDataSource
HttpDataSource在dataconfig.xml中的配置看起來應(yīng)該像這樣:?
<dataSource type="HttpDataSource" baseUrl="http://host:port/" encoding="UTF-8" connectionTimeout="5000" readTimeout="10000"/>
屬性:
-
baseUrl (可選): 在Dev/QA/Prod 環(huán)境中,host/port改變時(shí),你會(huì)用到它。使用這個(gè)屬性,你可以找出配置到solrconfig.xml的變化。
-
encoding (可選): 默認(rèn)情況下,encoding是response 頭使用的encoding.你可以使用這個(gè)屬性去覆蓋默認(rèn)值。
-
connectionTimeout (可選):默認(rèn)值是5000ms
-
readTimeout (可選):?默認(rèn)值是10000ms
在?data-config.xml中的配置
?一個(gè) xml/http data source中的實(shí)體有下面一些屬性,也可以有上面提到的默認(rèn)屬性。
-
processor (必需的) : 它的值應(yīng)該是 "XPathEntityProcessor"
-
url (必需的) :? REST API要使用這個(gè)api. (能夠被模板化). 假設(shè)數(shù)據(jù)源是一個(gè)文件,那么url應(yīng)該是這個(gè)文件的位置。
-
stream (可選) : 如果xml很大,那么它應(yīng)該設(shè)為true
-
forEach (必需的) : xpath表達(dá)式,通過這個(gè)表達(dá)式可以取得想要的值。 如果這里有多個(gè)想要的值,那么將xpath表達(dá)式用“|”分開。如果useSolrAddSchema設(shè)為true的話,這個(gè)是可以被忽略的。
-
xsl (可選):使用xsl對(duì)xml進(jìn)行預(yù)處理。你需要提供一個(gè)文件系統(tǒng)的全路徑,或者一個(gè)url。
-
useSolrAddSchema (可 選): Set it's value to 'true' if the xml that is fed into this processor has the same schema as that of the solr add xml. No need to mention any fields if it is set to true.
域能夠有以下這些屬性?(此外還有那些默認(rèn)值):
-
xpath (必需的) : 記錄中的一列,也就是域的xpath表達(dá)式?. 如果 該域并不來自任何的一個(gè)單一的xml屬性,xpath是可以被忽略的. 我們可以通過轉(zhuǎn)化器來使用多個(gè)xml屬性來合成該域。如果一個(gè)域被聲明成多值的,如果xpath表達(dá)式生成的也是多值的,那么 XPathEntityProcessor將會(huì)自動(dòng)處理它,而不需要我們做額外的工作。
-
commonField :?能夠被設(shè)為 (true或者false),假設(shè)這個(gè)是true值,一旦一個(gè)記錄中有這樣的域,那么其他記錄被寫索引的時(shí)候,這個(gè)域也會(huì)跟著記錄被寫到索引里面。
如 果 一個(gè)API支持分塊數(shù)據(jù)(當(dāng)一個(gè)數(shù)據(jù)集太大時(shí)),可能需要多次調(diào)用才能完成這個(gè)處理過程。XPathEntityprocessor 通過轉(zhuǎn)換器支持這個(gè)特性。如果轉(zhuǎn)換器返回的的行帶有屬性“hasMore”,并且這個(gè)屬性的值等于true,那么Processor 將會(huì)使用同樣的url模板發(fā)出令一次請(qǐng)求(實(shí)際的url是需要重新計(jì)算的)。一個(gè)轉(zhuǎn)換器也可以傳遞一個(gè)完整的url路徑,這個(gè)url被包含在屬性 “nextUrl”中,nextUrl的值必需是一個(gè)完整的url。
XPathEntityProcessor 通過實(shí)現(xiàn)streaming parser來支持取得xpath子集的操作。完整的xpath是不被支持的,但是常見的應(yīng)用都是受支持的。
HttpDataSource 例子
下載 在DB 部分中的“完全導(dǎo)入”例子,試著去體驗(yàn)一下。我們將在這里例子中為slashotRSS建立索引。
這個(gè)例子的data-config配置看起來像這樣。
<dataConfig> <dataSource type="HttpDataSource" /> <document> <entity name="slashdot" pk="link" url="http://rss.slashdot.org/Slashdot/slashdot" processor="XPathEntityProcessor" forEach="/RDF/channel | /RDF/item" transformer="DateFormatTransformer"> <field column="source" xpath="/RDF/channel/title" commonField="true" /> <field column="source-link" xpath="/RDF/channel/link" commonField="true" /> <field column="subject" xpath="/RDF/channel/subject" commonField="true" /> <field column="title" xpath="/RDF/item/title" /> <field column="link" xpath="/RDF/item/link" /> <field column="description" xpath="/RDF/item/description" /> <field column="creator" xpath="/RDF/item/creator" /> <field column="item-subject" xpath="/RDF/item/subject" /> <field column="date" xpath="/RDF/item/date" dateTimeFormat="yyyy-MM-dd'T'hh:mm:ss" /> <field column="slash-department" xpath="/RDF/item/department" /> <field column="slash-section" xpath="/RDF/item/section" /> <field column="slash-comments" xpath="/RDF/item/comments" /> </entity> </document> </dataConfig>
這個(gè)data-config有很多值得借鑒的地方。 我建議你看下SlashdotRSS的結(jié)構(gòu)圖,它有一些頭部元素,例如title、link、subject。這些元素將分別通過xpath語法映射到source、source-link、subject這些solr域。這個(gè)種子有多個(gè)item元素,這些元素包含了真正的新聞信息。所以,我們希望做得是,為每一個(gè)item元素建立一個(gè)文檔。
XPathEntityprocessor?是一行一行的讀取xml文件的(這里的行指的是一個(gè)xml元素)。它使用屬性“forEach”去識(shí)別每一行?。在這個(gè)例子一種“forEach”的值是 '/RDF/channel?|?/RDF/item'。也就是說這個(gè)xml有兩種類型的行(這里使用一個(gè)OR的xpath語法,用以支持多個(gè)類型) 。當(dāng)遇到一個(gè)行的時(shí)候,它會(huì)在行的域聲明中讀取盡量多的域。在這個(gè)例子中,當(dāng)它讀到行“/RDF/channel”時(shí),它將會(huì)得到3個(gè)域。它處理完這個(gè)行 的時(shí)候,它就會(huì)意識(shí)到,這個(gè)行并沒有pk這個(gè)域的值,于是它并不會(huì)試圖去建立一個(gè)solr文檔(即使它去做,它也會(huì)失敗)。但是這個(gè)三個(gè)域都有一個(gè)屬性 commonField ,并且它的值是true,所以它將會(huì)保留這個(gè)域的值,以便后面的行可以使用
它繼續(xù)前進(jìn),然后遇到/RDF/item ,接著一個(gè)個(gè)處理這些行。它將會(huì)取得除了那個(gè)三個(gè)域之外的所有域。但是因?yàn)樗麄兪莄ommon field。處理器會(huì)把公共域也加到這個(gè)記錄中,然后寫入索引。
transformer=DateFormatTransformer 又是什么呢?你可以看一下DateFormatTransformer有關(guān)部分。
你 可以使用這些特性來從REST API ,例如 rss、atom、xml、其他solr服務(wù)器、甚至是格式良好的xhtml文檔,建立索引。我們的xpath語法有它自己的限制(不支持通配符,只可以 是全路徑),但是一般的應(yīng)用是絕對(duì)沒有問題的,而且它是基于streaming parser的,它非常快,并且在讀取非常大的xml文件的時(shí)候,它的內(nèi)存消耗始終保持如一。它不支持命名空間,它卻可以處理帶有命名空間的xml文件。 當(dāng)你處理帶有命名空間的xpath的時(shí)候,你需要做的是,丟棄命名空間部分,只留下其他的部分(例如,這個(gè)標(biāo)簽,相對(duì)應(yīng)的xpath部分是 subject)。很容易,是吧?而且你不需要寫一行代碼,好好享受吧。
?注意 :?不像數(shù)據(jù)庫,如果你使用XPathEntityProcessor,想忽略域聲明是不可能。域通過你聲明的xpaths來從xml中解析相應(yīng)的數(shù)據(jù)。
例子: 索引 wikipedia
利用下面的data-config.xml文件可以對(duì)wikipedia的數(shù)據(jù)建立索引。從wikipedia下載下來的pages-articles.xml.bz2文件解壓之后大概有18g。
<dataConfig> <dataSource type="FileDataSource" encoding="UTF-8" /> <document> <entity name="page" processor="XPathEntityProcessor" stream="true" forEach="/mediawiki/page/" url="/data/enwiki-20080724-pages-articles.xml"> <field column="id" xpath="/mediawiki/page/id" /> <field column="title" xpath="/mediawiki/page/title" /> <field column="revision" xpath="/mediawiki/page/revision/id" /> <field column="user" xpath="/mediawiki/page/revision/contributor/username" /> <field column="userId" xpath="/mediawiki/page/revision/contributor/id" /> <field column="text" xpath="/mediawiki/page/revision/text" /> <field column="timestamp" xpath="/mediawiki/page/revision/timestamp" /> </entity> </document> </dataConfig>
schema.xml中有關(guān)的部分如下所示:
<field name="id" type="integer" indexed="true" stored="true" required="true"/> <field name="title" type="string" indexed="true" stored="false"/> <field name="revision" type="sint" indexed="true" stored="true"/> <field name="user" type="string" indexed="true" stored="true"/> <field name="userId" type="integer" indexed="true" stored="true"/> <field name="text" type="text" indexed="true" stored="false"/> <field name="timestamp" type="date" indexed="true" stored="true"/> <field name="titleText" type="text" indexed="true" stored="true"/> ... <uniqueKey>id</uniqueKey> <copyField source="title" dest="titleText"/>
為7278241個(gè)文章建立索引大概花了2個(gè)小時(shí)40分,內(nèi)存使用量的峰值在4G左右。
使用“增量導(dǎo)入”命令
只 有SqlEntitiProcessor支持增量數(shù)據(jù)!XPathEntityProcessor還沒有實(shí)現(xiàn)它。所以,不幸運(yùn)的是,現(xiàn)在還不能為“增量導(dǎo) 入”提供支持。如果你想要在XPathEntityProcessor中實(shí)現(xiàn)這些方法,你可以在EntityProcessor.java中看看這些方法 的解釋。
Extending the tool with APIs
我們所展現(xiàn)的例子確實(shí)沒有多大價(jià)值,單靠配置xml文件就滿足所有的需求是不可能的。所以我們提供了一些抽象類,可以通過這些方法來提高功能。
Transformer
每一條從數(shù)據(jù)庫中取得的數(shù)據(jù)能夠被直接處理掉,或者通過它創(chuàng)建一個(gè)全新的域,它設(shè)置能夠返回多行數(shù)據(jù)。配置文件必須像下面那樣設(shè)置。
<entity name="foo" transformer="com.foo.Foo" ... />
?注意-- trasformer的值必須是一個(gè)可以使用的classname。如果class包是
'org.apache.solr.handler.dataimport'
,包名可以被忽略。solr.也是可以使用的,如果這個(gè)class在solr的一個(gè)包下的話。這個(gè)規(guī)則適應(yīng)所有的可插入的類,像DataSource、EntityProcessor、Evaluator。?
類Foo必須繼承抽象類 org.apache.solr.hander.dataimport.Transformer.這個(gè)類只有一個(gè)抽象方法。
transformer這個(gè)屬性可以有多個(gè)transformers() (比如 ?transformer="foo.X,foo.Y" ) 之間用逗號(hào)隔開。 transformers 會(huì)形成一條處理鏈。它們將會(huì)按照它們的排列順序起作用。
public abstract class Transformer { /** * The input is a row of data and the output has to be a new row. * * @param context The current context * @param row A row of data * @return The changed data. It must be a Map if it returns * only one row or if there are multiple rows to be returned it must * be a List> */ public abstract Object transformRow(Map row, Context context); }
Context 是一個(gè)抽象的類,它提供上下文關(guān)系,這可能在處理數(shù)據(jù)的時(shí)候要用到。
另外,類Foo,可以選擇不不實(shí)現(xiàn)這個(gè)抽象類,而只需要下面這個(gè)方法
public Object transformRow(Map row)
So there is no compile-time dependency on the DataImportHandler API
它的配置是靈活的。它允許用戶向標(biāo)簽entity和field提供任意的屬性。tool將會(huì)讀取數(shù)據(jù),并將它傳給實(shí)現(xiàn)類。如果Transformer需要額外的的信息,它可以從context中取得。
正則表達(dá)式轉(zhuǎn)換器
tool它提供了一個(gè)內(nèi)嵌的轉(zhuǎn)換器,叫做正則表達(dá)式轉(zhuǎn)換器。它可以使用正則表達(dá)式從原數(shù)據(jù)中解析出我們想要的值。 org.apache.solr.handler.dataimport.RegexTransformer 是它的名字. 因?yàn)樗鼘儆谀J(rèn)的包,所以它的包名是可以被忽略的。
例子:?
<entity name="foo" transformer="RegexTransformer" query="select full_name , emailids from foo"/> ... /> <field column="full_name"/> <field column="firstName" regex="Mr(/w*)/b.*" sourceColName="full_name"/> <field column="lastName" regex="Mr.*?/b(/w*)" sourceColName="full_name"/> <field column="mailId" splitBy="," sourceColName="emailids"/> </entity>
?
屬性
RegexTransfromer只對(duì)屬性中有regex或者splitBy的域起作用。所有的屬性我們列在下面。
-
regex : 這是要匹配的正則表達(dá)式。regex和splitBy兩者必有其一。如果沒有,這個(gè)域?qū)⒉粫?huì)被正則表達(dá)式轉(zhuǎn)換器處理。
-
sourceColName : 正則表達(dá)式起作用的列。. 如果這個(gè)這個(gè)屬性不存在,那么source將等同域target。
-
splitBy : 如果正則表達(dá)式,是被用來分割一個(gè)字符串以獲得多個(gè)值,那么使用這個(gè)。
-
replaceWith : 跟 屬性regex一起使用。相當(dāng)于我們平常使用的方法 new?String().replaceAll(,?)
這 里,屬性‘regex’和‘sourceColName’是轉(zhuǎn)換器自定義的屬性。它從resultSet中讀取域‘full_name’的值,然后轉(zhuǎn)換 它,并將結(jié)果分別傳給‘firstName’和‘lastName’。所以,盡管查詢結(jié)果只返回一列“full_name”,但solr document依然可以獲得額外的兩個(gè)域“firstName”和‘lastName’。
域'emailids'? 是一個(gè)用逗號(hào)分隔著的值。 所以,我們最終可以從emailids得到一個(gè)以上的emial id。mailid 在solr中應(yīng)該被定義為多值的。
腳本轉(zhuǎn)換器
你可以使用javascript 或者其他的 腳本語言來寫轉(zhuǎn)換器,只要java支持這種腳本。在這里我們應(yīng)該使用java 6.
<dataConfig> <script><![CDATA[ function f1(row) { row.put('message', 'Hello World!'); return row; } ]]></script> <document> <entity name="e" pk="id" transformer="script:f1" query="select * from X"> .... </entity> </document> </dataConfig>
?
-
你可以在dataConfig結(jié)點(diǎn)中設(shè)置script 標(biāo)簽。默認(rèn)的語言是javascript。你當(dāng)然可以使用另外一種語言,你可以通過script標(biāo)簽中的屬性language去設(shè)置它。(必須有java6的支持)。
-
你可以寫任意多的轉(zhuǎn)換函數(shù)。每個(gè)函數(shù)必須接受一個(gè)相當(dāng)于 Map的row變量,然后要返回一個(gè)row。(轉(zhuǎn)換以后)
-
通過在實(shí)體中指定 transformer=“script:”來使一個(gè)實(shí)體使用腳本函數(shù)。
-
在上面的data-config中,對(duì)于結(jié)果中返回的實(shí)體e的每一個(gè)行,javascript函數(shù)都將被執(zhí)行一次。?
-
執(zhí)行機(jī)制跟一個(gè)java的轉(zhuǎn)換器是一樣的。在Transformer 中有兩個(gè)參數(shù) (transformRow(Map,Context ))。在javascript中,第二個(gè)參數(shù)被忽略了,但它一樣是起作用的。
日期格式轉(zhuǎn)換器
這里有一個(gè)內(nèi)嵌的轉(zhuǎn)換器,叫做DateFormatTransformer(日期格式轉(zhuǎn)換器) ,這個(gè)在將字符型時(shí)間轉(zhuǎn)換成java.util.Date的類型的時(shí)候是很有用的。
<field column="date" xpath="/RDF/item/date" dateTimeFormat="yyyy-MM-dd'T'hh:mm:ss" />
屬性
日期格式轉(zhuǎn)換器只對(duì)帶有屬性“dateTimeFormat”的域才起作用。其他屬性如下所示。
-
dateTimeFormat : 轉(zhuǎn)換使用的格式。這個(gè)必須服從java的SimpleDateformat。
-
sourceColName : 要使用日期轉(zhuǎn)換的列。如果沒有設(shè)定這個(gè)值,那么源列跟目標(biāo)域的名稱是一樣的。
上面的域的定義在RSS例子中有使用,以轉(zhuǎn)換RSS種子項(xiàng)中的時(shí)間格式。
數(shù)字格式轉(zhuǎn)換器
能將一個(gè)字符串轉(zhuǎn)換成一個(gè)數(shù)字,使用的是java中類NumberFormat。例子:
<field column="price" formatStyle="number" />
默認(rèn)情況下,類Numberformat使用系統(tǒng)的本地格式去轉(zhuǎn)換一個(gè)字符串,如果你需要指定一個(gè)不同的本地類型的話,你可以像下面這樣指定。例子:
<field column="price" formatStyle="number" locale="de-DE" />
屬性
數(shù)字格式轉(zhuǎn)換器 只對(duì)那些帶有屬性“formatStyle”的域有用。
-
formatStyle : 解析這個(gè)域所需要的格式。這個(gè)屬性的值必須是(number|percent|integer|currency)中的一個(gè)。可以參考 java
NumberFormat .
-
sourceColName : 要使用數(shù)字轉(zhuǎn)換的列。如果沒有設(shè)定這個(gè)值,那么源列跟目標(biāo)域的名稱是一樣的。
-
locale : 要轉(zhuǎn)換的字符串所使用的國際化格式。如果沒有設(shè)定這個(gè)值,它的默認(rèn)值是系統(tǒng)的國際化格式。它的值必須是language-country。例如 en-US。
模板轉(zhuǎn)換器
使用DataImportHandler中強(qiáng)大的模板引擎來創(chuàng)建或者設(shè)定一個(gè)域的值。例如:
<entity name="e" transformer="TemplateTransformer" ..> <field column="namedesc" template="hello${e.name},${eparent.surname}" /> ... </entity>
這里模板的規(guī)則跟‘query’、‘url’的規(guī)則是一樣的。它主要能幫我們將多個(gè)值連到一起,或者忘域值注入其他的字符。這個(gè)轉(zhuǎn)換器只對(duì)擁有屬性‘template’的域起作用。
屬性
-
template : 模板字符串。上面的例子中有兩個(gè)占位符,‘${e.name}和${eparent.surname}’。 In the above example there are two placeholders '${e.name}' and '${eparent.surname}' . 兩個(gè)值都必須存在,否則這個(gè)模板將不會(huì)起作用。
自定義模板轉(zhuǎn)換器
如 果你需要在將數(shù)據(jù)送給solr之前,對(duì)數(shù)據(jù)進(jìn)行一些處理,你可以寫一個(gè)你自己的轉(zhuǎn)換器。讓我們來看一個(gè)例子。在我們的schema中我們有一個(gè)單值的域叫 做‘a(chǎn)rtistName’,類型是String。這個(gè)域的值包含了多個(gè)單詞,例如‘Celine Dion’,這里有一個(gè)問題 ,這個(gè)值包含一些開頭空格和結(jié)尾空格,這些空格不是我們想要的。solr的WhitespaceAnalyze在這里用不上,因?yàn)椋覀儾⒉幌氚堰@個(gè)字符 串切詞了。一個(gè)可以選擇的解決方案就是自己寫一個(gè)TrimTransformer。
一個(gè)簡(jiǎn)單的TrimTransformer
package foo; public class TrimTransformer { public Object transformRow(Map row) { String artist = row.get("artist"); if (artist != null) row.put("ar", artist.trim()); return row; } }
不需要去繼承任何類。這個(gè)類只需要有transformRow 方法,就像上面的那樣。DataImportHandler會(huì)自動(dòng)辨別它,并使用反射機(jī)制來調(diào)用它。你可以在你的data-config.xml文件中這樣來設(shè)置:
<entity name="artist" query="..." transformer="foo.TrimTransformer"> <field column="artistName" /> </entity>
一個(gè)通用的TrimTransformer
假設(shè),你想寫一個(gè)通用的TrimTransformer,這樣你就不用將要處理的列寫在的代碼里面。這里,我們需要在data-config.xml中設(shè)一個(gè)標(biāo)記來表示這個(gè)域是否要應(yīng)用這個(gè)轉(zhuǎn)換器。
<entity name="artist" query="..." transformer="foo.TrimTransformer"> <field column="artistName" trim="true" /> </entity>
現(xiàn)在,你需要去繼承 Transformer ?這個(gè)抽象類,并使用Context中的API來獲得實(shí)體中的域,并獲得域中的屬性,檢查標(biāo)記有沒有被設(shè)值。
package foo; public class TrimTransformer extends Transformer { public Map transformRow(Map row, Context context) { List> fields = context.getAllEntityFields(); for (Map field : fields) { // Check if this field has trim="true" specified in the data-config.xml String trim = field.get("trim"); if ("true".equals(trim)) { // Apply trim on this fied String columnName = field.get("column"); // Get this field's value from the current row String value = row.get(columnName); // Trim and put the updated value back in the current row if (value != null) row.put(columnName, value.trim()); } } return row; } }
如果域是多值的,那么返回值將會(huì)是一個(gè)list而不是單單一個(gè)對(duì)象,而且需要被恰當(dāng)?shù)奶幚怼D憧梢詫ataImprotHandler打包成一個(gè)jar包,然后再擴(kuò)展Transformer和Context。
EntityProcessor(實(shí)體處理器)
默認(rèn)的情況下,每個(gè)實(shí)體都會(huì)被sqlEntityProcessor處理。在系統(tǒng) 使用RDBMS作為數(shù)據(jù)源的時(shí)候,它很適用。對(duì)于其他的數(shù)據(jù)源,例如 REST 或者不是sql的數(shù)據(jù)源 ,你可以選擇 繼承 org.apache.solr.handler.dataimport.Entityprocessor . 這個(gè)抽象類。它被設(shè)計(jì)成從實(shí)體中一行一行的讀取數(shù)據(jù)。最簡(jiǎn)單的實(shí)現(xiàn)自己的實(shí)體處理器的方式是 繼承EntityProcessorBase ,然后重寫方法 public?Map?nextRow() method。 'EntityProcessor'依賴于 數(shù)據(jù)源來獲取數(shù)據(jù)。數(shù)據(jù)源的返回類型對(duì)實(shí)體處理器來說是很重要的。下面是一些內(nèi)嵌的實(shí)體處理器。
SqlEntityProcessor
它是默認(rèn)的,數(shù)據(jù)源必須是DataSource類型的,在這里默認(rèn)的情況下使用的是jdbcDataSource。
XPathEntityProcessor
處理XML類型的數(shù)據(jù)源。數(shù)據(jù)源的類型必須是DataSource類型的,這種類型的數(shù)據(jù)源有HttpDataSource和FileDatasource類型。
FileListEntityProcessor
簡(jiǎn)單的處理器,它能夠從文件系統(tǒng)中得到文件的集合。這個(gè)系統(tǒng)基于一些標(biāo)準(zhǔn),它不使用數(shù)據(jù)源,下面是實(shí)體的屬性:
-
fileName :(必須) 辨別文件的正則表達(dá)式
-
baseDir : (必須) 根目錄(虛擬路徑)
-
recursive :?是否要遞歸的獲取文件,默認(rèn)是false。
-
excludes : 匹配文件名的正則表達(dá)式
-
newerThan :?一個(gè)數(shù)字參數(shù) .?使用格式 ( yyyy-MM-dd?HH:mm:ss ) . 它可以是一個(gè)datemath 類型的字符串,例如:('NOW-3DAYS'). 需要加單引號(hào)。它也可以是一個(gè)變量,像${var.name}這樣。
-
olderThan :?一個(gè)數(shù)字參數(shù) . 跟上一條的規(guī)則是一樣的
-
rootEntity :根實(shí)體的值必須是false,除非你想索引文件名。位置直接在下面的是根實(shí)體,這就意味著根實(shí)體產(chǎn)生的行都將被當(dāng)成一個(gè)document存放在 lucene里面。但是,在這個(gè)例子里面,我們并不想為每個(gè)文件建立一個(gè)document,我們想對(duì)x實(shí)體產(chǎn)生的行建立document,因?yàn)閷?shí)體f的屬 性rootEntiry等于false,所以在直接位于實(shí)體f下面的實(shí)體將成為根實(shí)體,它所產(chǎn)生的行將會(huì)被當(dāng)成一個(gè)document。
-
dataSource :它必須被設(shè)為null值,因?yàn)檫@里并不需要使用任何的數(shù)據(jù)源,即是說,我們將不會(huì)創(chuàng)建Datasource的實(shí)例。(在大多數(shù)的情況下,只有一個(gè)數(shù)據(jù)源,jdbc數(shù)據(jù)源,所有的實(shí)體都用,在這里,數(shù)據(jù)源是沒有必要的。)
例子:
<dataConfig> <dataSource type="FileDataSource" /> <document> <entity name="f" processor="FileListEntityProcessor" fileName=".*xml" newerThan="'NOW-3DAYS'" recursive="true" rootEntity="false" dataSource="null"> <entity name="x" processor="XPathEntityProcessor" forEach="/the/record/xpath" url="${f.fileAbsolutePath}"> <field column="full_name" xpath="/field/xpath"/> </entity> </entity> <document> <dataConfig>
千萬要注意rootEntiry這個(gè)屬性,由這個(gè)處理器所產(chǎn)生的域有 fileAbsolutePath,fileSize,fileLastModified,fileName .
CachedSqlEntityProcessor
應(yīng)該說,這是SqlEntityProcessor的一個(gè)擴(kuò)展,這個(gè)處理器通過緩存一些行,來減少數(shù)據(jù)庫查詢。它幾乎對(duì)根實(shí)體沒有用,因?yàn)檫@個(gè)實(shí)體中只有一個(gè)sql語句被執(zhí)行了。
Example 1.
<entity name="x" query="select * from x"> <entity name="y" query="select * from y where xid=${x.id}" processor="CachedSqlEntityProcessor"> </entity> <entity>
這個(gè)例子的用法跟下面的是一樣的,一個(gè)查詢被執(zhí)行完,它的結(jié)果被存儲(chǔ)起來,下次這個(gè)查詢?cè)俦粓?zhí)行的的時(shí)候,它將會(huì)從緩存中取出結(jié)果并返回。
Example 2:
<entity name="x" query="select * from x"> <entity name="y" query="select * from y" processor="CachedSqlEntityProcessor" where="xid=x.id"> </entity> <entity>
這個(gè)例子跟前一個(gè)的區(qū)別在于屬性‘where’。這個(gè)例子中,查詢語句將從表中取回所有的數(shù)據(jù),并把他們都放 在緩存中。其中的關(guān)鍵就在域 屬性‘where’。緩存使用y中的xid作為鍵值,實(shí)體被查詢的時(shí)候x.id的值就會(huì)被計(jì)算出來,我們首先會(huì)在緩存中找匹配的數(shù)據(jù),接著返回。
?
在屬性where中,=號(hào)之前的值是y中的列,=號(hào)之后的值是計(jì)算出來的要在緩存中查找的值。
DataSource(數(shù)據(jù)源)
? org.apache.solr.handler.dataimport.DataSource 能被繼承。
public abstract class DataSource { /** * Initializes the DataSource with theContext
and * initialization properties. ** This is invoked by the
DataImporter
after creating an * instance of this class. * * @param context * @param initProps */ public abstract void init(Context context, Properties initProps); /** * Get records for the given query.The return type depends on the * implementation . * * @param query The query string. It can be a SQL for JdbcDataSource or a URL * for HttpDataSource or a file location for FileDataSource or a custom * format for your own custom DataSource. * @return Depends on the implementation. For instance JdbcDataSource returns * an Iterator> */ public abstract T getData(String query); /** * Cleans up resources of this DataSource after use. */ public abstract void close(); }
?它必須在數(shù)據(jù)源的定義部分被配置。
<dataSource type="com.foo.FooDataSource" prop1="hello"/>
JdbcdataSource
這個(gè)是默認(rèn)的,它的聲明如下:
public class JdbcDataSource extends DataSource >>
?
它可以一條一條的遍歷數(shù)據(jù)庫,每一行數(shù)據(jù)被當(dāng)作一個(gè)Map。
HttpDataSource
XPathEntityProcessor使用這個(gè)數(shù)據(jù)源 . 它的聲明如下:
public class HttpDataSource extends DataSource
FileDataSource
這個(gè)很像HttpDataSource . 它的聲明如下:
public class FileDataSource extends DataSource
The attributes are:
-
basePath : (可選的)? ,得到所需要的值時(shí)必須的基本路徑。
-
encoding : (可選的)當(dāng)文件編碼跟平臺(tái)編碼不一樣的時(shí)候,應(yīng)當(dāng)設(shè)定這個(gè)值。
Boosting , Skipping documents(提高文檔的得分,或者跳過文檔)
我們還可以在運(yùn)行的時(shí)候提高一個(gè)文檔的得分,或者跳過某一個(gè)特定的文檔。
可以通過自定義轉(zhuǎn)化器,增加一個(gè)屬性,并將它設(shè)為true,這樣就可以跳過這個(gè)文檔了。可以通過,增加一個(gè)屬性docBoost ,屬性是文檔的評(píng)分的這種方式給文檔打分。Write a custom Transformer to add a value $skipDoc with a value 'true' to skip that document. To boost a document with a given value add $docBoost with the boost value
在?solrconfig.xml中增加數(shù)據(jù)源
我們也可以在solrconfig.xml中配置數(shù)據(jù)源,屬性是一樣的,只是方式稍微有點(diǎn)不同。?
?????
????
????? <requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler">
??? <lst name="defaults">
????? <str name="config">/home/username/data-config.xml</str>
????? <lst name="datasource">
???????? <str name="driver">com.mysql.jdbc.Driver</str>
???????? <str name="url">jdbc:mysql://localhost/dbname</str>
???????? <str name="user">db_username</str>
???????? <str name="password">db_password</str>
????? </lst>
??? </lst>
? </requestHandler>
結(jié)構(gòu)圖
下面的這個(gè)圖顯示了一般的配置文件的邏輯流程。
上面的這個(gè)圖表達(dá)了這樣的一個(gè)意思:一共有三個(gè)數(shù)據(jù)源,兩個(gè)關(guān)系數(shù)據(jù)庫的數(shù)據(jù)源,和一個(gè)http/xml的數(shù)據(jù)源。
?
???????? jdbc1 和jdbc2 是JdbcDataSource ,它配置在solrconfig.xml文件中。
-
http是一個(gè)HttpDataSource類型的數(shù)據(jù)源。
-
根實(shí)體是一個(gè)叫做a的表,它使用jdbc1作為它的數(shù)據(jù)源。實(shí)體一般都與表名相同。
-
實(shí)體A有兩個(gè)子實(shí)體 B 和C?。B使用http數(shù)據(jù)源,C使用jdbc2數(shù)據(jù)源。
-
在執(zhí)行一個(gè)full-import的命令的時(shí)候,根實(shí)體A會(huì)首先被執(zhí)行。
-
由實(shí)體A導(dǎo)出的每一行,都會(huì)被傳給實(shí)體B和實(shí)體C。
-
B和C通過占位符來使用實(shí)體A中的數(shù)據(jù)。占位符:${A.a(chǎn)}。
-
B 有一個(gè)url屬性
-
C 有一個(gè)query屬性
-
-
C 有兩個(gè)轉(zhuǎn)換器 ‘f’和‘g’。
-
由C產(chǎn)生的每一行數(shù)據(jù),都會(huì)被有序的傳給 'f '和‘g’(轉(zhuǎn)換器是鏈?zhǔn)降模从行虻?。每個(gè)轉(zhuǎn)換器都能夠改變輸入的值。在這里轉(zhuǎn)換器‘g’將從一行數(shù)據(jù)(f(c .1))中產(chǎn)生兩行數(shù)據(jù)。?
-
最近將每個(gè)實(shí)體的結(jié)果合并成為一個(gè)文檔。
-
請(qǐng)注意:從C產(chǎn)生的中間結(jié)果,例如C.1 c.2 ,f(c.1) f(c.2),都將被忽略掉。
-
域聲明
域 的聲明,能夠幫助我們通過提供一些額外的信息得到那些不能自動(dòng)獲取到的值。它依賴于結(jié)果集中的列。在dataConfig里面配置的域,一般情況下應(yīng)該跟 schema配置的一樣。它應(yīng)該自動(dòng)繼承schema.xml中的所有的域。但是,你不能增加一些額外的域。? 那么,什么時(shí)候增加域聲明呢?
-
當(dāng)實(shí)體處理器所產(chǎn)生的域的名字,跟相應(yīng)的域在schema.xml中的名字不一樣的時(shí)候。
-
當(dāng)內(nèi)嵌的轉(zhuǎn)換器需要一些額外的信息來決定哪個(gè)域要處理,以及該怎么處理的時(shí)候。
-
XPathEntityprocessor 或者其他的處理器,顯示的要求一些額外的信息的時(shí)候。
關(guān)于行(row)和多值域
行 在DataimportHandler中的表現(xiàn)形式是一個(gè)Map。在這個(gè)map里面,key是域的名字,value可以任何一個(gè)合法的solr 類型。value也能夠是合法的solr類型的聚集(這將會(huì)映射到一個(gè)多值域)。如果數(shù)據(jù)源是RDBMS的話,一般是不會(huì)產(chǎn)生多值域的。當(dāng)然我們可以通過 加一個(gè)子實(shí)體的方式來產(chǎn)生多值域。這里子實(shí)體返回的多個(gè)域,相當(dāng)于父實(shí)體的一個(gè)多值域。如果數(shù)據(jù)源是xml的話,產(chǎn)生多值域是一件相當(dāng)簡(jiǎn)單的事情。
變量
變 量是指最終代替那些占位符的值。這是一個(gè)多級(jí)的map,每一個(gè)命名空間都是一個(gè)map,命名空間使用.分隔。例如 占位符 ${item.ID}, 'item'是一個(gè)命名空間(也是一個(gè)map),ID是這個(gè)命名空間下的一個(gè)值。我們很容易推導(dǎo)出 占位符 ${item.x.ID} 這里x是另外一個(gè)map。變量的值能夠從Context中獲得,也可以在RDMS的query屬性中或者h(yuǎn)ttp數(shù)據(jù)源的url屬性中使用類似${}的占 位符獲得。
使用函數(shù)來自定義query和url的格式
?命名空間這個(gè)概念在這里也是相當(dāng)?shù)挠杏玫摹S脩艨赡芟胍獋饕粋€(gè)經(jīng)過計(jì)算的值給 query或者url,比如這里有一個(gè)Data類型的數(shù)據(jù),但是你的數(shù)據(jù)源只支持另外一種格式的數(shù)據(jù)源。我們提供了一些函數(shù),或許它們能夠幫你完成一些事情。
-
formatDate : 它可以像這樣去使用, '${dataimporter.functions.formatDate(item.ID,?yyyy-MM-dd?HH:mm)}' 。它的第一個(gè)參數(shù)是一個(gè)合法的變量,第二個(gè)參數(shù)是一種時(shí)間格式(這里使用的格式工具是SimpledateFormat),The first argument can be a valid value from the VariableResolver and the second cvalue can be a a format string (use SimpledateFormat) . 它可以是一個(gè)經(jīng)過計(jì)算的值,它使用solr的時(shí)間表示方式。(要注意,它必須被單引號(hào)括起來
-
escapeSql : 使用它可以對(duì)特別的sql 字符串進(jìn)行包裝。例子 : '${dataimporter.functions.escapeSql(item.ID)}' . 這里只使用一個(gè)參數(shù),這個(gè)參數(shù)必須是一個(gè)合法的VaraiableResolver.
-
encodeUrl : 使用這個(gè)對(duì)url進(jìn)行編碼。例子e: '${dataimporter.functions.encodeUrl(item.ID)}' . 只使用一個(gè)參數(shù),這個(gè)參數(shù)必須是一個(gè)合法的VariableResolver
訪問請(qǐng)求參數(shù)
我們可以使用'request'命名空間來訪問傳遞給http 請(qǐng)求的參數(shù)。例如 '${dataimporter.request.command}' 將會(huì)返回被執(zhí)行的命令。任何參數(shù)都可以通過這種方式得到。
交互式的開發(fā)模式Interactive Development Mode
這是一個(gè)很酷的,并且功能強(qiáng)大的工具。它能夠幫助你通過圖形界面來建立一個(gè)dataconfig.xml文檔。你可以通過
http://host:port/solr/admin/dataimport.jsp
?來訪問它。 以下是它的特性:
-
這個(gè)界面有兩個(gè)板塊,RHS是用來獲取輸入的,LHS是用來顯示輸出的。
-
當(dāng)你點(diǎn)擊debug now 按鈕的時(shí)候,它將會(huì)執(zhí)行配置文件,并且顯示結(jié)果文檔。
-
你可以通過start和rows這兩個(gè)參數(shù)來調(diào)試 類似從115開始到118這樣的文檔。
-
選擇 'verbose'選項(xiàng)表示你想要得到一些關(guān)于中間步驟的信息。包括query產(chǎn)生的數(shù)據(jù),傳給轉(zhuǎn)換器的數(shù)據(jù),以及轉(zhuǎn)換器產(chǎn)生的數(shù)據(jù)。
-
如果在運(yùn)行過程中發(fā)生了異常,那么LHS板塊將顯示異常信息。
-
fields是由實(shí)體產(chǎn)生的。當(dāng)域沒有在schema.xml中聲明,也沒有在dataConfig.xml有聲明的時(shí)候,轉(zhuǎn)換器就不會(huì)對(duì)該域進(jìn)行處理了。
屏幕快照
哪里可以找到它?
DataimportHandler是solr的新加的特性。
-
從?
Solr website ?下載一個(gè)最新的版本?。
-
通過 Full Import 的例子來感受一下。
在Solr JIRA.的?
SOLR-469
你可以查看到有關(guān)DataImporthandler的一些開發(fā)討論。
第三部分:SOLR的db-data-config.xml高級(jí)進(jìn)階(處理CLOB和BLOB)
我們?cè)谑褂胹olr處理數(shù)據(jù)庫時(shí),很多時(shí)候需要處理一下數(shù)據(jù)庫中的CLOB、BLOB字段,對(duì)于這兩種字段如何處理,下面以代碼的形式給大家演示,(不用寫Java代碼啊)
1)定義數(shù)據(jù)源
<dataSource name= "ora" driver= "oracle.jdbc.OracleDriver" url= "...." /> <datasource name= "ds-BlobField" type= "FieldStreamDataSource" />
2.)寫一個(gè)blob字段處理
<entity dataSource= "ora" name= "meta" query= "select id, filename,content, bytes from documents" transformer="ClobTransformer" > <field column= "ID" name= "id" /> <field column= "FILENAME" name= "filename" /> <field column="CONTENT" name="CONTENT" clob="true" />
?? ??? ??? ????
<entity dataSource="ds-BlobField" processor="TikaEntityProcessor" url="FILE_CONTENT"
?? ??? ??? ??? ??? ?dataField="ATTACH.FILE_CONTENT">
?? ??? ??? ??? ??? ?<field column="text" name="FJ_FILE_CONTENT" /><!-- 全局搜索 -->
?? ??? ??? ??? ??? ?<field column="Author" name="FJ_FILE_AUTHOR" meta="true" />
?? ??? ??? ??? ?</entity>
</entity>
這里簡(jiǎn)單介紹一下,上述藍(lán)色字體是處理clob必須的,紅色字體是處理blob必須的。
還是比較簡(jiǎn)單的吧。如果你還沒看明白,,我也沒轍了。哦,這里需要說明一下,使用上述代碼需要依賴幾個(gè)jar包:
tika-app-0.9.jar(巨大20M,不過非常好用,對(duì)于PDF、Excel、Word、PPT、RTF、TAR 、ZIP 等等吧,好多自己查吧。)
http://apache.etoak.com//pdfbox/1.6.0/pdfbox-app-1.6.0.jar
activation-1.1.jar
mail-1.4.1.jar
缺少了就跑不起來了,;)
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
