Lucene暴走之巧用内存倒排索引高效识别垃圾数据

2024-05-15 03:38

本文主要是介绍Lucene暴走之巧用内存倒排索引高效识别垃圾数据,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

[size=medium]
识别垃圾数据,在一些大数据项目中的ETL清洗时,非常常见,比如通过关键词
(1)过滤垃圾邮件
(2)识别yellow网站
(3)筛选海量简历招聘信息
(4)智能机器人问答测试
........
各个公司的业务规则都不一样,那么识别的算法和算法也不一样,这里提供一种思路,来高效快速的根据关键词规则识别垃圾数据。

下面看下需求:

业务定义一些主关键词若干少则几百个,多则几千个上万个,例如:
[/size]

公司
机车厂
化纤厂
建设局
实业集团
中心店
桑拿中心
托管中心

然后又定义一些辅助关键词若干:

原告
被告
委托代理人
当事人
申请人
上诉人

[size=medium]
ok,关键词有了,下面看下业务规则 , 规定如下:

任意辅助关键词组合主关键词都命中的情况下,并且词组间距不大于20者,即为合法数据。

嗯,没听懂?,那么来看个例子,一段文本如下:
[/size]

上诉人北京金建出租汽车有限公司因机动车x通事故责任纠纷一案

[size=medium]
使用IK细粒度分词后可能是这样的:
[/size]

上诉人|上诉|人|北京|金|建出|出租汽车|出租|汽车|有限公司|有限|有|限|公司|因|机动车|机动|车|x通事故|x通|通事|事故责任|事故|责任|纠纷|一案|

[size=medium]
根据规则,辅助词库与主词库都命中,而且中间的词组间距不超过20的,为合法数据,
本例子中:
辅助关键词:上诉人
主关键词: 公司
都出现,中间词组是12个,所以符合业务规则,即为合法数据,

假设,改变原来的文本的公司为集团,再次测试:
[/size]

上诉人北京金建出租汽车有限集团因机动车x通事故责任纠纷一案

使用IK细粒度分词后可能是这样的:

上诉人|上诉|人|北京|金|建出|出租汽车|出租|汽车|有限集团|有限|有|限|集团|因|机动车|机动|车|x通事故|x通|通事|事故责任|事故|责任|纠纷|一案|

[size=medium]
这次因为辅助关键词库命中了,但是主关键词库没有命中,所以会被当成垃圾数据。

上面是帮助理解业务的一个例子,下面再分析下,性能问题,假设主关键词有500个,辅助关键词有10个,那么任意
两两组合的可能就是500*10=5000个规则条件,也就是意味着需要最坏情况下,需要匹配5000次才能识别一篇垃圾数据,当然如果你参与识别垃圾的文本不是一个字段,而是二个字段,一个是标题,一个是内容,那么最后真正的匹配次数是5000*2=10000词匹配,如果再加上距离条件,那么查询的复杂度将会大幅度增加,这个时候,如果我们使用正则匹配
效率可想而知,使用正则每次全文扫描定位,耗时非常之慢,这时候我们假设有一种快捷的hash算法,来提升性能,毫无疑问,类似的倒排索引将会是解决这种问题的神器。

因为只需要构建一次临时索引,不落地磁盘,不与IO打交道,仅仅在内存和cpu之间参与计算匹配,而且规则方式非常灵活,可以有更多的规则制定进来,特别是关键词匹配这块,lucene索引非常完美的解决了这个问题。当然如此这种计算,非常耗CPU,对内存的占用不是非常高,因为一条数据,处理完之后,他占用的资源,会被释放。

在线情况下:平均几十毫秒左右就能识别一条数据,已经接近实时了

离线情况下:在集成到hadoop或者Spark这种分布式的集群里面,也是非常给力的,因为通常情况下spark和hadoop比较耗IO和磁盘而加入这种运算将会大大提升集群的资源使用效率。

本项目只是给出了一个根据关键词识别的例子,这个项目拿到你们本地也许并不能立刻使用,但是相似的业务,但是它提供了一种思路,大部分情况下,改动少许代码,即可适应大部分类似的业务。
核心代码如下:
[/size]


package com.anytrust.algo;

import com.anytrust.model.MonitorType;
import com.anytrust.tools.DictTools;
import org.apache.lucene.index.memory.MemoryIndex;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.BooleanQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wltea.analyzer.lucene.IKAnalyzer;

/**
* Created by qindongliang on 2016/1/7.
* 根据规则识别是否为垃圾数据
*/
public class CheckOneAlgo {

//IK中文分词器
IKAnalyzer analyzer=new IKAnalyzer(false);
//内存索引处理
MemoryIndex index = new MemoryIndex();

static {
//设置Lucene的boolean query条件数最大支持个数
BooleanQuery.setMaxClauseCount(10000);
}


static Logger logger= LoggerFactory.getLogger(CheckOneAlgo.class);


/**构建查询query
* @param type 根据类型构建
* */
private String buildQuery(MonitorType type){

StringBuffer sb =new StringBuffer("(");
for(String kw: DictTools.main_kws){//遍历主词库
switch (type) {
case LITIGATION://代表文书 0105
for (String hkw : DictTools.assist_kws) { //遍历辅助词库
sb.append("tc:\"").append(hkw + kw).append("\"~20 ");
}
break;
case ANNOUNCEMENT://公告 0104
sb.append("tc:\"").append(kw).append("\" ");
break;
default:
logger.error("未知类型:{}",type);
break;

}
}
sb.append(" ) ");
return sb.toString();
}


/***
* 对一段文本执行垃圾数据识别功能
* 返回true说明是有效数据
* 返回false说明是垃圾数据
* @param text 监测的文本
* @return
*/
public boolean checkDoc(String text,MonitorType type){
String query=buildQuery(type);
QueryParser parser = new QueryParser("", analyzer);
index.addField("tc", text, analyzer);
try {
float score = index.search(parser.parse(query));
if(score > 0.0f){
return true;//正确数据
}else{
return false;//垃圾数据
}

}catch (Exception e){
logger.error("识别垃圾数据异常!",e);
}finally {
index.reset();//重置index引擎,服复用类对象
}
return false;
}


}


[size=medium]有些关键词在Iteye博客会屏蔽,建议直接到github看:
Github地址:[url]https://github.com/qindongliang/lucene-garbage-check[/url]
[/size]
[b][color=green][size=large]
有什么问题 可以扫码关注微信公众号:我是攻城师(woshigcs),在后台留言咨询。
本公众号的内容是有关搜索和大数据技术和互联网等方面内容的分享,也是一个温馨的技术互动交流的小家园
[/size][/color][/b]
[img]http://dl2.iteye.com/upload/attachment/0104/9948/3214000f-5633-3c17-a3d7-83ebda9aebff.jpg[/img]

这篇关于Lucene暴走之巧用内存倒排索引高效识别垃圾数据的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/990702

相关文章

浅谈mysql的not exists走不走索引

《浅谈mysql的notexists走不走索引》在MySQL中,​NOTEXISTS子句是否使用索引取决于子查询中关联字段是否建立了合适的索引,下面就来介绍一下mysql的notexists走不走索... 在mysql中,​NOT EXISTS子句是否使用索引取决于子查询中关联字段是否建立了合适的索引。以下

SQL中如何添加数据(常见方法及示例)

《SQL中如何添加数据(常见方法及示例)》SQL全称为StructuredQueryLanguage,是一种用于管理关系数据库的标准编程语言,下面给大家介绍SQL中如何添加数据,感兴趣的朋友一起看看吧... 目录在mysql中,有多种方法可以添加数据。以下是一些常见的方法及其示例。1. 使用INSERT I

Python使用vllm处理多模态数据的预处理技巧

《Python使用vllm处理多模态数据的预处理技巧》本文深入探讨了在Python环境下使用vLLM处理多模态数据的预处理技巧,我们将从基础概念出发,详细讲解文本、图像、音频等多模态数据的预处理方法,... 目录1. 背景介绍1.1 目的和范围1.2 预期读者1.3 文档结构概述1.4 术语表1.4.1 核

MySQL 删除数据详解(最新整理)

《MySQL删除数据详解(最新整理)》:本文主要介绍MySQL删除数据的相关知识,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录一、前言二、mysql 中的三种删除方式1.DELETE语句✅ 基本语法: 示例:2.TRUNCATE语句✅ 基本语

怎样通过分析GC日志来定位Java进程的内存问题

《怎样通过分析GC日志来定位Java进程的内存问题》:本文主要介绍怎样通过分析GC日志来定位Java进程的内存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、GC 日志基础配置1. 启用详细 GC 日志2. 不同收集器的日志格式二、关键指标与分析维度1.

Java内存分配与JVM参数详解(推荐)

《Java内存分配与JVM参数详解(推荐)》本文详解JVM内存结构与参数调整,涵盖堆分代、元空间、GC选择及优化策略,帮助开发者提升性能、避免内存泄漏,本文给大家介绍Java内存分配与JVM参数详解,... 目录引言JVM内存结构JVM参数概述堆内存分配年轻代与老年代调整堆内存大小调整年轻代与老年代比例元空

MyBatisPlus如何优化千万级数据的CRUD

《MyBatisPlus如何优化千万级数据的CRUD》最近负责的一个项目,数据库表量级破千万,每次执行CRUD都像走钢丝,稍有不慎就引起数据库报警,本文就结合这个项目的实战经验,聊聊MyBatisPl... 目录背景一、MyBATis Plus 简介二、千万级数据的挑战三、优化 CRUD 的关键策略1. 查

python实现对数据公钥加密与私钥解密

《python实现对数据公钥加密与私钥解密》这篇文章主要为大家详细介绍了如何使用python实现对数据公钥加密与私钥解密,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录公钥私钥的生成使用公钥加密使用私钥解密公钥私钥的生成这一部分,使用python生成公钥与私钥,然后保存在两个文

MySQL之InnoDB存储引擎中的索引用法及说明

《MySQL之InnoDB存储引擎中的索引用法及说明》:本文主要介绍MySQL之InnoDB存储引擎中的索引用法及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录1、背景2、准备3、正篇【1】存储用户记录的数据页【2】存储目录项记录的数据页【3】聚簇索引【4】二

mysql中的数据目录用法及说明

《mysql中的数据目录用法及说明》:本文主要介绍mysql中的数据目录用法及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、版本3、数据目录4、总结1、背景安装mysql之后,在安装目录下会有一个data目录,我们创建的数据库、创建的表、插入的