背景:基于call客,来电和跟进记录等多个数据来源的用户文档,需要在更新是判断首来源的时间。

如对电话号码11xxxx来说,来电时间是今天,call客时间是昨天,而call客数据又可能因为网络原因晚上传上来,这样一来11xxxx这个用户document的来源时间需要更新成昨天。

分析:solr的默认update没有办法匹配业务的灵活的更新逻辑。更新逻辑如下,当更新来源时间的时候,如果新的来源时间比之前的来源时间晚,则保持之前的来源时间。

代码实现:

package custom.solr;
import java.io.IOException;
import org.apache.lucene.util.BytesRef;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.core.SolrCore;
import org.apache.solr.handler.component.RealTimeGetComponent;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.update.AddUpdateCommand;
import org.apache.solr.update.processor.UpdateRequestProcessor;
import org.apache.solr.update.processor.UpdateRequestProcessorFactory;
import org.apache.solr.util.RefCounted; public class ConditionUpdateProcessFactory extends UpdateRequestProcessorFactory
{
@Override
public UpdateRequestProcessor getInstance(SolrQueryRequest req, SolrQueryResponse rsp, UpdateRequestProcessor next)
{
return new ConditionalUpdateProcessor(req, rsp, next);
}
} class ConditionalUpdateProcessor extends UpdateRequestProcessor
{
public static final String ORIGIN_TIMESTAMP = "origin_timestamp";
public ConditionalUpdateProcessor(SolrQueryRequest req, SolrQueryResponse rsp, UpdateRequestProcessor next)
{
super(next);
core = req.getCore();
} private final SolrCore core; @Override
public void processAdd(AddUpdateCommand cmd) throws IOException
{
SolrInputDocument newDoc = cmd.getSolrInputDocument();
BytesRef indexedId = cmd.getIndexedId();
RefCounted<SolrIndexSearcher> newestSearcher = core.getRealtimeSearcher();
SolrIndexSearcher searcher;
long lookup;
searcher = (SolrIndexSearcher) newestSearcher.get();
lookup = searcher.lookupId(indexedId);
//if not exists
if (lookup < 0)
{super.processAdd(cmd);
}
SolrInputDocument oldDoc = RealTimeGetComponent.getInputDocument(core, indexedId);
Object newOriginTimestamp = newDoc.getFieldValue(ORIGIN_TIMESTAMP);
Object oldOriginTimestamp = oldDoc.getFieldValue(ORIGIN_TIMESTAMP);
if (newOriginTimestamp != null && oldOriginTimestamp != null)
{
if (Long.valueOf(oldOriginTimestamp.toString()) < Long.valueOf(newOriginTimestamp.toString()))
{
newDoc.setField(ORIGIN_TIMESTAMP, oldOriginTimestamp);
}
}
// pass it up the chain
super.processAdd(cmd);
} }

1.将该类编译后生成jar包放到 /var/lib/solr/plugins目录下,或者你任意指定一个目录。

2.配置solrconfig.xml加载该jar包。(注意修改jar包或者solrconfig.xml之后要reload collection)

<lib dir="/var/lib/solr/plugins" />

3.配置solrconfig.xml的默认update用哪个chain名字。

<requestHandler name="/update" class="solr.UpdateRequestHandler">
<!-- See below for information on defining
updateRequestProcessorChains that can be used by name
on each Update Request
-->
<lst name="defaults">
<str name="update.chain">condition</str>
</lst>
</requestHandler>

以及solrconfig.xml chain的流程。

<updateRequestProcessorChain name="condition">
<processor class="solr.LogUpdateProcessorFactory" />
<processor class="solr.DistributedUpdateProcessorFactory" />
<processor class="custom.solr.ConditionUpdateProcessFactory" />
<processor class="solr.RunUpdateProcessorFactory" />
</updateRequestProcessorChain>

*关于为什么放在DistibutedUpdateProcessFactory之后。

https://wiki.apache.org/solr/Atomic_Updates

2017.01.12优化:

如下场景时,上面代码会出现问题:

老的数据没有立即commit,还保存在TLog中,此时RealTimeGetComponet.getInputDocument方法获取不到老数据,导致处理逻辑不符合期望,来源时间不正确。

代码优化如下:

SolrInputDocument oldDoc = RealTimeGetComponent.getInputDocumentFromTlog(core, indexedId);
if (oldDoc == null)
{
oldDoc = RealTimeGetComponent.getInputDocument(core, indexedId);
}

Solr Update插件自定义Update Chain按条件更新索引的更多相关文章

  1. [jQuery]jQuery DataTables插件自定义Ajax分页实现

    前言 昨天在博客园的博问上帮一位园友解决了一个问题,我觉得有必要记录一下,万一有人也遇上了呢. 问题描述 园友是做前端的,产品经理要求他使用jQuery DataTables插件显示一个列表,要实现分 ...

  2. 【JAVA】FOR UPDATE 和 FOR UPDATE NOWAIT 区别 (转)

    1.for update 和 for update nowait 的区别:首先一点,如果只是select 的话,Oracle是不会加任何锁的,也就是Oracle对 select 读到的数据不会有任何限 ...

  3. [转]oracle for update和for update nowait的区别

    1概念小结:(针对以下引用区域内容) 1.1 普通select语句不加锁. 1.2 for update和for update nowait都试图将符合条件的数据加上行级锁.用于排斥其他针对这个表的写 ...

  4. Oracle 中 for update 和 for update nowait 的区别

    原文出处http://bijian1013.iteye.com/blog/1895412 一.for update 和 for update nowait 的区别 首先一点,如果只是select 的话 ...

  5. oracle for update和for update nowait

    原文地址:http://www.cnblogs.com/quanweiru/archive/2012/11/09/2762223.html 1.for update 和 for update nowa ...

  6. sql: oracle, for update和for update nowait的区别

    1. oracle for update和for update nowait的区别 http://www.cnblogs.com/quanweiru/archive/2012/11/09/276222 ...

  7. oracle for update和for update nowait(for update wait)的区别

    1.for update 和 for update nowait 的区别: 1.oracle 中执行select 操作读取数据不会有任何限制,当另外一个进程在修改表中的数据,但是并没有commit,所 ...

  8. oracle for update和for update nowait的区别 - 转

    1.for update 和 for update nowait 的区别: 首先一点,如果只是select 的话,Oracle是不会加任何锁的,也就是Oracle对 select 读到的数据不会有任何 ...

  9. oracle for update和for update nowait 的区别

    原文地址:http://www.cnblogs.com/quanweiru/archive/2012/11/09/2762223.html 1.for update 和 for update nowa ...

随机推荐

  1. 摄像头ov2685中关于sensor id 设置的相关的寄存器地址【转】

    本文转载自:http://blog.csdn.net/morixinguan/article/details/51220992 OV2685 : CHIP_ID address : 0x300A   ...

  2. multiple web application host under the same website on IIS (authentication mode)

    第一种方式,修改forms的name how to set the forms authentication cookie path assume you have already solved th ...

  3. Opencv保存摄像头视频&&各种编码器下视频文件占用空间对比

    打开视频文件或摄像头视频需要使用Opencv中的VideoCapture类,保存视频或摄像头视频到本地磁盘,需要使用Opencv中的VideoWriter类,使用都很简单,这篇文章就记录一下Video ...

  4. [BZOJ 1741] Asteroids

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=1741 [算法] 将每颗小行星的行,列相连,问题就转化为了求这张图的最小覆盖 由kon ...

  5. com/opensymphony/xwork2/spring/SpringObjectFactory.java:220:-1问题出现的原因及解决办法

    转自:https://blog.csdn.net/shinchan_/article/details/37818927 com/opensymphony/xwork2/spring/SpringObj ...

  6. git拉取远端改变,但是不覆盖本地的修改

    1.git stash 2.git  fetch weixin-old-remote 3.git rebase weixin-old-remote/main151028_wxpay_main15100 ...

  7. (Go)09.指针赋值修改示例

      答案: 1 package main 2 import ( 3 "fmt" 4 ) 5 6 7 func modify(p *int) { 8 fmt.Println(p) 9 ...

  8. [Apple开发者帐户帮助]六、配置应用服务(3)创建地图标识符和私钥

    要与MapKit JS通信,您将使用Maps私钥对一个或多个开发人员令牌进行签名. 首先注册地图标识符以识别您的应用.为使用MapKit JS的每个应用注册地图标识符.接下来创建并下载启用了MapKi ...

  9. HDU3085 Nightmare Ⅱ

    题目: Last night, little erriyue had a horrible nightmare. He dreamed that he and his girl friend were ...

  10. go的语言结构

    一.文件名.关键字与标识符 1.1 文件名 1.go 的源文件已 .go 为后缀名 2.文件名已小写组成 如:simple.go 3.如多个部分组成可用"_" 分割 4.不要包含有 ...