ES的同义词、扩展词、停止词热更新方案

最近要实现的一些功能需要让ES的同义词、扩展词、停止词能够热更新,达到让搜索更精确的目的。在网上看了很多相关的博客,现在热更新的方案已经实施成功,现在来总结一下。

ES版本:5.5.2

IK分词器版本:5.5.2

扩展词、停止词 

我的ES使用的中文分词器是IK分词器,IK分词器支持一种热更新的方案,部署一个web服务器,提供一个http接口,通过modified和tag两个http响应头,来提供词语的热更新。

同义词

同义词的配置,Elasticsearch自带了一个synonym同义词插件,但是该插件只能使用文件或在分析器中静态地配置同义词,如果需要添加或修改,需要修改配置文件和重启,使用方式不够友好,我需要的是热更新。

 

基于以上的现有的方案,再加上我参考了两篇博客,决定采用这样的方案:

(1)修改ik分词器源码,然后手动支持从mysql中每隔一定时间,自动加载新的词库

(2)修改一款别人自研的一个可动态维护同义词的插件,也是同样的从mysql中每隔一定时间,自动加载新的词库

(3)在项目中对相应的文档用定时任务进行重建文档操作,因为热更新的词对旧文档无效。

附上两位的博客地址:
Elasticsearch之IK分词器热更新
一个简易的Elasticsearch动态同义词插件
万分感谢两位~

好了,下面进入正题

一、扩展词、停止词

1.下载IK分词器的源码

进入github,找到对应版本的ik分词器,下载源码,我这里是5.5.2版本的ES,所以我下载5.5.2版本的IK分词器

https://github.com/medcl/elasticsearch-analysis-ik/tree/v5.5.2
这是一个maven工程,下载下来后直接导入到eclipse中进行改造

2.修改源码

先看一下下载下来的源码的文件目录

这个-root后缀的项目就是我刚下载下来的ik的源码,这个源码上面的那个项目是我修改过后的源码。

由于我们是要动词库,所以我们直奔dic目录,找到Dictionary类,先看看它这个是怎么加载词典的。

看看他的构造函数:

initial方法:

根据上面原博主的思路,是在这个Dictionnary类中,写两个方法,用jdbc去mysql中分别查询扩展词和停止词,然后放到对应的词典中。然后再这个初始化的方法中,像原生的代码那样也调用一下这两个方法。再建立一个监控线程,定时去加载扩展词和停止词。

我在原博主的的基础上,把配置的数据库的属性初始化的时候封装到Dictionnary类中的一个属性中,包括加载的sql和监控线程隔多久进行一次扫描。这样方便进行配置。

(1)、先在Dictionnary类定义两个自己要的属性

DB_PROPERTIES属性是我们自己建的属性文件的文件名字
myProperties属性是用来把读取到的属性文件里的属性装起来

(2)、在config目录下创建db.properties文件

(3)、在构造方法中读取db.properties,并提供几个获取属性的方法

	private Dictionary(Configuration cfg) {
		this.configuration = cfg;
		this.props = new Properties();
		this.myProperties = new Properties();
		this.conf_dir = cfg.getEnvironment().configFile().resolve(AnalysisIkPlugin.PLUGIN_NAME);
		Path configFile = conf_dir.resolve(FILE_NAME);
		Path myFile = cfg.getConfigInPluginDir().resolve(DB_PROPERTIES);
		logger.info("加载属性文件db.properties的路径:" + myFile);
		InputStream input = null;
		InputStream myInput = null;
		File file = myFile.toFile();
		logger.info("file文件:" + file);
		try {
			myInput = new FileInputStream(file);
		} catch (FileNotFoundException e1) {
			logger.error("db.properties未找到", e1);
		}
		try {
			logger.info("try load config from {}", configFile);
			input = new FileInputStream(configFile.toFile());
		} catch (FileNotFoundException e) {
			conf_dir = cfg.getConfigInPluginDir();
			configFile = conf_dir.resolve(FILE_NAME);
			try {
				logger.info("try load config from {}", configFile);
				input = new FileInputStream(configFile.toFile());
			} catch (FileNotFoundException ex) {
				// We should report origin exception
				logger.error("ik-analyzer", e);
			}
		}
		if (input != null) {
			try {
				props.loadFromXML(input);
			} catch (InvalidPropertiesFormatException e) {
				logger.error("ik-analyzer", e);
			} catch (IOException e) {
				logger.error("ik-analyzer", e);
			}
		}
		try {
			myProperties.load(myInput);
		} catch (IOException e) {
			logger.error("加载db.properties文件失败!", e);
		}
	}

获取几个属性的方法

	private String getUrl() {
		String url = myProperties.getProperty("url");
		return url;
	}

	private String getUser() {
		String user = myProperties.getProperty("user");
		return user;
	}

	private String getPassword() {
		String password = myProperties.getProperty("password");
		return password;
	}

	private int getInterval() {
		Integer interval = Integer.valueOf(myProperties.getProperty("interval"));
		return interval;
	}

	private String getExtWordSql() {
		String extWordSql = myProperties.getProperty("extWordSql");
		return extWordSql;
	}

	private String getStopWordSql() {
		String stopWordSql = myProperties.getProperty("stopWordSql");
		return stopWordSql;
	}

(3)、写两个从数据库中读取扩展词和停止词的方法,再写一个重新加载扩展词和停止词的方法给监控线程去调用

	private void loadMySQLExtDict() {
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;
		try {
			logger.info("query ext dict from mysql, " + getUrl());
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection(getUrl(), getUser(), getPassword());
			stmt = conn.createStatement();
			String extWordSql = getExtWordSql();
			if(!StringUtils.isNullOrEmpty(extWordSql)){
				rs = stmt.executeQuery(extWordSql);
				while (rs.next()) {
					String theWord = rs.getString("main_keyword");
					logger.info("main_keyword ext word from mysql: " + theWord);
					_MainDict.fillSegment(theWord.trim().toCharArray());
				}
			}

		} catch (Exception e) {
			logger.error("erorr", e);
		} finally {
			if (rs != null) {
				try {
					rs.close();
				} catch (SQLException e) {
					logger.error("error", e);
				}
			}
			if (stmt != null) {
				try {
					stmt.close();
				} catch (SQLException e) {
					logger.error("error", e);
				}
			}
			if (conn != null) {
				try {
					conn.close();
				} catch (SQLException e) {
					logger.error("error", e);
				}
			}
		}
	}

	private void loadMySQLStopDict() {
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;
		try {
			logger.info("query stop dict from mysql, " + getUrl());
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection(getUrl(), getUser(), getPassword());
			stmt = conn.createStatement();
			String stopWordSql = getStopWordSql();
			if(!StringUtils.isNullOrEmpty(stopWordSql)){
			rs = stmt.executeQuery(stopWordSql);
				while (rs.next()) {
					String theWord = rs.getString("main_keyword");
					logger.info("main_keyword stop word from mysql: " + theWord);
					_St
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值