solr 4.2 使用外掛鏈來完善、簡化增量index邏輯
業務背景
之前做村淘的時候開發過一個外掛,即動態的根據商品的類目判定該商品是不是要被和諧,所以瞭解到在update商品資訊的時候,商品是肯定會經過一個由若干Processor組成的chain最終進入底層索引的
現在遇到的問題是這樣的,當前的商品邏輯比較複雜,有很多不是從db裡得到的欄位,進索引時會根據業務邏輯做相應的處理,例如時間間隔,title,以及離線的一些分數,例如商品預測質量分等。全量索引時邏輯是完全可控,但是增量的索引如果預設使用小白版本的update方式就會導致後臺的web端邏輯承載了太多的搜尋引擎相關的邏輯,很重,而且每次業務邏輯有過改動以後,都需要把相同的邏輯java端寫一份,web端寫一份,然後code review,不出意外的話也是經常出錯。。所以痛定思痛決定開發solr的update外掛來從根本上解決增量的問題,把web端同志解救出來。
UpdateRequestProcessorChain
預設的chain是由
- LogUpdateProcessorFactory
- DistributedUpdateProcessorFactory
- RunUpdateProcessorFactory
構成的,而根據solr官方文件解釋,DistributedUpdateProcessorFactory是預設在RunUpdateProcessorFactory的前面出現的,這是為了支援solrcloud的功能。
Begining with Solr4.0 all UpdateRequestProcessorChains which include RunUpdateProcessorFactory, but do not include an implementation of the DistributingUpdateProcessorFactory will have an instance of DistributedUpdateProcessorFactory automaticly injected immediately prior to the RunUpdateProcessorFactory.
所以即使我業務上配置的updateRequestProcessorChain並沒有顯示的DistributedUpdateProcessorFactory,而在實際程式碼執行的時候也會把DistributedUpdateProcessorFactory放置在RunUpdateProcessorFactory前,於是在使用mychain來update文件的時候,也會構造出來一個有4個ProcessorFactory的chain用於進行處理。而至於softCommit等相關配置只與最終的UpdateHandler相關,即RunUpdateProcessorFactory會呼叫UpdateHandler來進行commit等相關操作,所以新的chain不會影響softCommit等相關配置。
<updateRequestProcessorChain name="mychain" >
<processor class="com.niuniu.update.plugin.NiuniuProcessorFactory" />
<processor class="solr.LogUpdateProcessorFactory" />
<processor class="solr.RunUpdateProcessorFactory" />
</updateRequestProcessorChain>
那麼要如何配置我們自定製的updateRequestProcessorChain要先了解一下solr.LogUpdateProcessorFactory、DistributedUpdateProcessorFactory以及solr.RunUpdateProcessorFactory對應的是什麼功能,然後就知道自己應該把定製化的ProcessorFactory放在chain的哪一塊。
- LogUpdateProcessorFactory是用來打log的
- RunUpdateProcessorFactory是用來把更新的內容持久化到磁碟的
所以我們的業務相關的ProcessorFactory應該在chain的最頂端,也即官方文件說的:
Configuring Individual Processors as Top-Level Plugins
參考官方的定製化ProcessorFactory開發文件:
package my.solr;
import java.io.IOException;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.update.AddUpdateCommand;
import org.apache.solr.update.processor.UpdateRequestProcessor;
import org.apache.solr.update.processor.UpdateRequestProcessorFactory;
public class ConditionalCopyProcessorFactory extends UpdateRequestProcessorFactory
{
@Override
public UpdateRequestProcessor getInstance(SolrQueryRequest req, SolrQueryResponse rsp, UpdateRequestProcessor next)
{
return new ConditionalCopyProcessor(next);
}
}
class ConditionalCopyProcessor extends UpdateRequestProcessor
{
public ConditionalCopyProcessor( UpdateRequestProcessor next) {
super( next );
}
@Override
public void processAdd(AddUpdateCommand cmd) throws IOException {
SolrInputDocument doc = cmd.getSolrInputDocument();
Object v = doc.getFieldValue( "popularity" );
if( v != null ) {
int pop = Integer.parseInt( v.toString() );
if( pop > 5 ) {
doc.addField( "cat", "popular" );
}
}
// pass it up the chain
super.processAdd(cmd);
}
}
部署完成以後,就可以在增量更新(add or update)的時候指定好update.chain=mychain就可以滿足我們的業務需求了
curl "http://localhost:8983/solr/production/update?update.chain=mychain" -H "Content-Type: text/xml" --data-binary '
<add>
<doc>
<field name="id">10</field>
<field name="brand_name">福特</field>
<field name="car_model_name">野馬</field>
<field name="standard_name">中規</field>
<field name="remark">康桑密達</field>
</doc>
</add>'
目前中文的文件較少特此記錄。
參考