网上有不少关于如何使用lucene完成实时搜索功能的文章。鉴于lucene的实现机制,绝大多数解决办法都是采用一定频率访问lucene索引,发现变更,然后搜索数据,返回结果。这种办法只能达到准实时效果,且会带来磁盘的I/O消耗。
抛开在lucene架构下能否找到更好的解决办法不谈,我们试着考虑到底是什么需求促使我们去寻找实时搜索lucene的解决方法的。想必大多数情况下,都是希望能够实时获取满足了某种条件的数据,而后对其进行计算或展示吧。既然如此,那么我们在对数据流处理时,直接匹配流中的数据岂不是更好?也只有这样做才能做到真正意义上的实时效果。这样看下来,其实我们只要有一个能够支持lucene查询语法的实时计算引擎就可以达到目的了。开源系统Tripod就是依据此思路构建起的兼容lucene查询语法的计算引擎。使用时只要集成其提供的api,设置好匹配条件,然后不断传入待匹配数据就可以实现对数据流的实时搜索了。
Tripod使用非常简单,其主要功能都集中在tripod-engine模块中,可通过如下maven依赖引入tripod-engine模块。
<dependency>
<groupId>org.datayoo.tripod</groupId>
<artifactId>tripod-engine</artifactId>
<version>1.0.0</version>
</dependency>
示例代码如下:
{
...
// 创建TripodEngine
TripodEngine tripodEngine = createTripodEngine();
// 构造测试数据文档
Map<String, TermEntity[]> dataMap = TripodTestHelper.createDataMap();
// 匹配文档
tripodEngine.match(dataMap, true);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
protected static TripodEngine createTripodEngine() {
List<FieldMetadata> fieldMetadatas = new LinkedList<FieldMetadata>();
FieldMetadata fieldMetadata = new FieldMetadata("title", 2);
fieldMetadatas.add(fieldMetadata);
fieldMetadata = new FieldMetadata("content", 1);
fieldMetadatas.add(fieldMetadata);
/*
* 初始化TripodEngine,传入待处理的文档对象的字段信息,缺省字段及Idf计算辅助接口
* */
TripodEngine tripodEngine = new TripodEngine(fieldMetadatas, fieldMetadata,
new IdfCounterImpl());
// 设置引擎在匹配时计算相关度
tripodEngine.setScoring(true);
// 文档匹配监听器,当规则匹配文档后,通过该接口回调传回匹配结果
TripodListener tripodListener = new TripodPrintListener();
// yoolerEngine
// .addYoolerRule("test", "(中办&title:中办)^2 任命 形式主义", yoolerListener);
// 向引擎添加匹配规则
tripodEngine.addTripodRule("test1", "\"第5代 领导\" 任命 形式主义", tripodListener);
return tripodEngine;
}
示例代码的执行结果为:
test1 : 0.066580
Tripod不止支持对数据进行实时匹配,还可以向lucene一样对匹配结果进行打分。示例中的输出结果即测试数据命中匹配规则后的相关分值。Tripod支持的打分算法与lucene一致,但实现细节及数据环境有差异,所以分值不完全相同,但其表现的与匹配条件的相关趋势是一致的,在使用时需要注意。如果要了解Tripod的更多详情,可以参见链接https://github.com/colorknight/tripod。