【热更新IK词典】ElasticSearch IK 自动热更新原理与实现
一、热更新原理
elasticsearch开启加载外部词典功功能后,会每60s间隔进行刷新字典。具体原理代码如下所示:
public void loadDic(HttpServletRequest req,HttpServletResponse response){
String eTag =req.getParameter("If-None-Match");
try {
OutputStream out= response.getOutputStream();
List<String> list=new ArrayList<String>();
list.add("中华人民共和国");
list.add("我爱你爱我");
String oldEtag = list.size() + "";
StringBuffer sb=new StringBuffer();
if (oldEtag != eTag) {
for (String str : list) {
if(StringUtils.isNotBlank(str)){
sb.append("\r\n");
}
sb.append(str+"\r\n");
}
}
String data=sb.toString();
response.setHeader("Last-Modified", String.valueOf(list.size()));
response.setHeader("ETag",String.valueOf(list.size()));
response.setContentType("text/plain; charset=gbk");
out.write(data.getBytes());
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
二、配置说明
我们公司以及用户常用的分词器为 IK 分词器,其中它有一个对应的核心配置文件名为:IKAnalyzer.cfg.xml,具体内容:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 扩展配置</comment>
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">custom/mydict.dic;custom/single_word_low_freq.dic</entry>
<!--用户可以在这里配置自己的扩展停止词字典-->
<entry key="ext_stopwords">custom/ext_stopword.dic</entry>
<!--用户可以在这里配置远程扩展字典 -->
<entry key="remote_ext_dict">location</entry>
<!--用户可以在这里配置远程扩展停止词字典-->
<entry key="remote_ext_stopwords">http://xxx.com/xxx.dic</entry>
</properties>
热更新 IK 分词使用方法,目前该插件支持热更新 IK 分词,通过上文在 IK 配置文件中提到的如下配置
<!--用户可以在这里配置远程扩展字典 --> <entry key="remote_ext_dict">location</entry> <!--用户可以在这里配置远程扩展停止词字典--> <entry key="remote_ext_stopwords">location</entry>
其中 location 是指一个 url,比如 http://yoursite.com/getCustomDict,该请求只需满足以下两点即可完成分词热更新。
该 http 请求需要返回两个头部(header)
1. 一个是 Last-Modified,
2. 一个是 ETag
这两者都是字符串类型,只要有一个发生变化,该插件就会去抓取新的分词进而更新词库。
该 http 请求返回的内容格式是一行一个分词,换行符用 \n 即可。
满足上面两点要求就可以实现热更新分词了,不需要重启 ES 实例。还需要注意的是获取词典的url,必须支持head访问
下面自己做的访问远程扩展词典的web api 服务接口(这一步可以直接忽略,看第三个即可,这里只是想说明也可以使用下面这种方式)
[HttpHead, HttpGet, HttpPost]
public async Task<HttpResponseMessage> GetDictionary(string path)
{
var response = this.Request.CreateResponse(HttpStatusCode.OK);
var content = File.ReadAllText(path);
response.Content = new StringContent(content, Encoding.UTF8);
response.Headers.Age = TimeSpan.FromHours(1);
response.Headers.ETag = EntityTagHeaderValue.Parse($"\"{content.ToMD5()}\"");
return response;
}
三、Tomcat 服务器自动更新
1、部署http服务
在这使用 tomcat8 作为 web 容器,先下载一个 tomcat8.5.16,然后上传到某一台服务器上(192.168.80.100)。
再执行以下命令
tar -zxvf apache-tomcat-8.5.16.tar.gz cd apache-tomcat-8.5.16/webapp/ROOT vim hot_ext.dic<br>智能移动机器人<br>vim hot_stopwords.dic<br>项目
之后验证一下这个文件是否可以正常访问 http://192.168.80.100:8080/hot.dic
通过tomcat访问词典,可以在不停用tomcat的情况下直接更新词典
2、修改ik插件的配置文件
修改 IK 核心配置文件 IKAnalyzer.cfg.xml 中的配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 扩展配置</comment>
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">custom/mydict.dic;custom/single_word_low_freq.dic</entry>
<!--用户可以在这里配置自己的扩展停止词字典-->
<entry key="ext_stopwords">custom/ext_stopword.dic</entry>
<!--用户可以在这里配置远程扩展字典 -->
<entry key="remote_ext_dict">http://192.168.80.100:8080/hot_ext.dic</entry>
<!--用户可以在这里配置远程扩展停止词字典-->
<entry key="remote_ext_stopwords">http://192.168.80.100:8080/hot_stopwords.dic</entry>
</properties>
3、验证
重启es,会看到如下日志信息,说明远程的词典加载成功了。

在浏览器中输入如下命令:http://localhost:9200/patent/_analyze?analyzer=ik_smart&text=智能移动机器人
正常情况下会分出很多次,这次发现只有这一个词,不会被分词,说明刚才配置远程的词库生效了,那么我们再换一个:北京雾霾,正常情况下可能会被分成两个词:北京、雾霾,如果我直接修改 tomcat 下的 hot_ext.dic 词库文件,增加一个关键词:北京雾霾,文件保存之后,查看es的日志会看到如下日志信息:

此时,再执行下面命令查看分词效果:http://localhost:9200/patent/_analyze?analyzer=ik_smart&text=北京雾霾
结果就是只有一个词,不会被分词了。
到这为止,可以实现动态添加自定义词库实现词库热更新。~~
代码实现
1.首先将di词典放在tomcat目录下
2.通过url读取配置文件
/**
* @Description 加载远程词典内容
* @param menuId 菜单id
* @param request http请求
* @return String 词典内容*/
@RequestMapping(value = "/loadDictionary", produces = "text/html;charset=UTF-8")
@ResponseBody
public String loadDictionary(Integer menuId, HttpServletRequest request) {
String filePath = getFilePath(request);
String context = readDictionary(filePath);
return context;
}
/**
* @Description 获取词典路径
* @param request HTTP请求
* @return String 词典路径*/
private String getFilePath(HttpServletRequest request) {
return "http://" + request.getServerName() + ":" + request.getServerPort() + "/" + "RemoteDictionary.dic";
}
/**
* @Description 读取远程词典
* @param filePath 词典路径
* @return String 词典内容*/
private String readDictionary(String filePath) {
StringBuffer document = new StringBuffer();
try {
URL url = new URL(filePath);
URLConnection conn = url.openConnection();
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null) {
document.append(line + System.getProperty("line.separator"));
}
reader.close();
} catch (MalformedURLException e) {
System.out.println("Unable to connect to URL: " + filePath);
} catch (IOException e) {
System.out.println("IOException when connecting to URL: " + filePath);
}
return document.toString();
}
3.将修改好的词典内容保存
/**
* @Description 保存词典
* @param menuId 菜单id
* @param context 词典内容
* @param request HTTP请求
* @return boolean 是否成果能够*/
@RequestMapping(value = "/saveDictionary")
@ResponseBody
public boolean saveDictionary(Integer menuId, String context, HttpServletRequest request) { //获取tomcat的路径
String filePath = System.getProperty("catalina.home")+"\\webapps\\ROOT\\RemoteDictionary.dic";
boolean result = writeDictionary(filePath, context);
return result;
}
/**
* @Description 上传词典
* @param filePath 词典路径
* @param content 修改的内容
* @return boolean 是否上传成功*/
private boolean writeDictionary(String filePath, String content) {
try {
File f = new File(filePath);
if (!f.exists()) {
return false;
}
OutputStreamWriter write = new OutputStreamWriter(new FileOutputStream(f), "UTF-8");
BufferedWriter writer = new BufferedWriter(write);
writer.write(content);
writer.close();
return true;
} catch (Exception e) {
return false;
}
}
【热更新IK词典】ElasticSearch IK 自动热更新原理与实现的更多相关文章
- 【自定义IK词典】Elasticsearch之中文分词器插件es-ik的自定义词库
Elasticsearch之中文分词器插件es-ik 针对一些特殊的词语在分词的时候也需要能够识别 有人会问,那么,例如: 如果我想根据自己的本家姓氏来查询,如zhouls,姓氏“周”. 如 ...
- Node.js + gulp 合并静态页模版,文件更新自动热重载。浏览器可预览
github地址:https://github.com/Liaozhenting/template 使用的是ejs的语法.其实你用什么文件后缀都可以,都是按ejs来解析. 模板文件放在componen ...
- solr6.3.0升级与IK动态词库自动加载
摘要:对于中文的搜索来说,词库系统是一个很比较重要的模块,本篇以IK分词器为例子,介绍如何让分词器从缓存或文件系统中自动按照一定频次进行加载扩展词库 Lucene.Solr或ElasticStack如 ...
- 另类Unity热更新大法:代码注入式补丁热更新
对老项目进行热更新 项目用纯C#开发的? 眼看Unity引擎热火朝天,无数程序猿加入到了Unity开发的大本营. 一些老项目,在当时ulua/slua还不如今天那样的成熟,因此他们选择了全c#开发:也 ...
- Elasticsearch IK+pinyin
如何在Elasticsearch中安装中文分词器(IK+pinyin) 如果直接使用Elasticsearch的朋友在处理中文内容的搜索时,肯定会遇到很尴尬的问题——中文词语被分成了一个一个的汉字 ...
- Unity3D热更新之LuaFramework篇[09]--资源热更新与代码热更新的具体实现
前言 在上一篇文章 Unity3D热更新之LuaFramework篇[08]--热更新原理及热更服务器搭建 中,我介绍了热更新的基本原理,并且着手搭建一台服务器. 本篇就做一个实战练习,真正的来实现热 ...
- Windows10安装Elasticsearch IK分词插件
安装插件 cmd切换到Elasticsearch安装目录下 C:\Users\Administrator>D: D:\>cd D:\Program Files\Elastic\Elasti ...
- elasticsearch ik分词
elasticsearch 默认并不支持中文分词,默认将每个中文字切分为一个词,这明显不符合我们的业务要求.这里就需要用到ik分词插件. 本文主要囊括了以下几部分,ik插件安装.ik用法介绍.自定义词 ...
- 使用 Elasticsearch ik分词实现同义词搜索(转)
1.首先需要安装好Elasticsearch 和elasticsearch-analysis-ik分词器 2.配置ik同义词 Elasticsearch 自带一个名为 synonym 的同义词 fil ...
- android游戏的增量更新(资源及代码的热更新)
需求当游戏需要更新时,不必让用户下载新的完整包,只需要通过游戏内部的更新系统自动更新差异包,达到节约用户流量和时间的目的. 大体思路:1.(游戏逻辑用lua等脚本编写的情况)这种方式的增量更新非常简单 ...
随机推荐
- JS-匀速运动-运动停止
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 关于线上js报错问题的思考
1.有没有可能对线上报错进行实时监控,只要线上报错出现就会以邮件的形式发出来. 2.有没有可能将每个模块和开发者联系起来,只要报错就直接报给开发者
- 3.node的url属性
node的url属性 1.parse: [Function: urlParse],2.format: [Function: urlFormat],3.resolve: [Function: urlRe ...
- 使用HttpClient以文件流的方式上传文件(非multipartFormData方式)
@Test public void testAdd() throws IOException { HttpPost post = new HttpPost("http://localhost ...
- 【BZOJ2007】[Noi2010]海拔 对偶图最短路
[BZOJ2007][Noi2010]海拔 Description YT市是一个规划良好的城市,城市被东西向和南北向的主干道划分为n×n个区域.简单起见,可以将YT市看作 一个正方形,每一个区域也可看 ...
- Thrift入门之mac下的安装流程
新建一个maven项目,先下载maven依赖 http://thrift.apache.org/download <dependency> <groupId>org.apac ...
- 170529、springMVC 的工作原理和机制
工作原理上面的是springMVC的工作原理图: 1.客户端发出一个http请求给web服务器,web服务器对http请求进行解析,如果匹配DispatcherServlet的请求映射路径(在web. ...
- C#知识
2018年10月29日 1.类可以定义的位置: (1)单独定义一个class,在program类的同一个文件内 (2)单独定义一个class,在program类的不同一个文件内 (3)类内定义clas ...
- Mongodb3.X版本的 的用户认证
一直使用公司的mongodb环境,本地的mongodb没有开启认证,为了环境更一致,决定加上本地mongodb的认证,不过在这个过程中发生了点波折. 我使用的是window版本的3.2,公司使用的是2 ...
- Python开发【模块】:内置模块
内置模块 1.__import__ # import app目录下的kingadmin.py文件 for app in conf.settings.INSTALLED_APPS: __import__ ...