Elastic:IK分词器分词、停用词热更新如何配置(一)基于API

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: 热更新是IK新版本中才支持的功能,其API需要满足两个要求:1、http请求中需要返回两个header,一个是Last-Modified,一个ETag。两个header都是字符串类型的。他们之中只要有一个发生变化,就会读取详情的数据并且更新词库,如果没有变化则不会更新词库。这个条件如果做前端的同学应该会比较熟悉,前端判断缓存是否更改时也是通过这两个条件。

1. 基于API实现热更新

ik的github有关于热更新的介绍
在这里插入图片描述

1.1 基于API的热更新的前置知识

热更新是IK新版本中才支持的功能,其API需要满足两个要求:
1、http请求中需要返回两个header,一个是Last-Modified,一个ETag。两个header都是字符串类型的。他们之中只要有一个发生变化,就会读取详情的数据并且更新词库,如果没有变化则不会更新词库。这个条件如果做前端的同学应该会比较熟悉,前端判断缓存是否更改时也是通过这两个条件。

Last-Modified是上次更新时间
ETag是实体标签(Entity Tag)的缩写,根据实体内容(文本数据)生成的一段hash字符串,可以通过它的标识数据的修改状态,当数据发生改变时,ETag也随之改变

2、返回的内容格式是一行一个分词,换行符用\n

1.2 思路

分词文件可以存放在一个文本文件中,注意文件需要时UTF-8编码格式的。放在nginx或者其他简易http server下,当文件修改时,http server会在客户端请求该文件时自动返回相应的Last-Modified和ETag。

另外可以做一个工具来从业务系统提取相关词汇,再更新到这个文件中

1.2.1 如何设置ETag的值

首先ETag要满足以下三个条件:
1、当文件内容改变时,ETag值跟着改变
2、计算简单,不会特别消耗CPU(因此就不能使用MD5、SHA128、SHA256等算法)
3、必须支持横向扩展,也就是在不同的服务器节点上生成的ETag是一样的

参考Nginx中ETag的生成:
由Last-Modified和content_length表示为16进制组合而成

etag = '"' + Long.toHexString(lastModified) + '-' + Long.toHexString(contentLength) + '"';

1.2.2 有了Last-Modified为什么还需要ETag?

开始之前我们先思考这个问题来帮助我们进一步理解热更新:有了Last-Modified为什么还需要ETag

1、原因就是因为某些服务器如果不能精确的获取到数据的最后修改时间的话,那么就无法通过Last-Modified来判断数据是否有更新了,就会导致词库更新不及时,出现延迟的问题。

2、Last-Modified一般只能精确到秒,如果数据更新的比较频繁的话,会导致识别不到更新,当然这点在IK分词器中不存在,因为IK分词器的热更新默认是一分钟获取一次。

3、如果我在一分钟内改了文件,发现改错了,又改回来了,那么这个时间虽然修改时间变了,但是因为内容没变,我是不希望更新它的。

综上所述,我们需要一个ETag来帮助我们判断是否更新了文本内容,同时ETag还需要根据文本内容来产生。

1.3 实操

1、创建分词库和停止词的文本文件
extend.dic

伍55
伍Benjamin
贵州贵阳
爽爽的贵阳
无敌尊贵氪金版iphone

stop.dic

那个
那些
的
这些
这个
是
不是

2、编写API
配置文件

ik:
  hot-word-path: "/Library/project/study/java/elasticsearch/elasticsearch-ik-hot-update/src/main/resources/extend.dic"
  stop-word-path: "/Library/project/study/java/elasticsearch/elasticsearch-ik-hot-update/src/main/resources/stop.dic"

api代码

@RestController
@RequestMapping("hot")
@Slf4j
public class HotUpdateController {

    @Value("${ik.hot-word-path}")
    private String hotWordFilePath;

    @Value("${ik.stop-word-path}")
    private String stopWordFilePath;

    /**
     * 获取分词、停止词
     * type 0分词,1停止词
     * @param response
     * @param type
     * @throws IOException
     */
    @RequestMapping("updateHotWord")
    public void hotWord(HttpServletResponse response,@RequestParam Integer type) throws IOException {
        if(type == null || (type != 0 && type != 1)){
            return;
        }
        File file = new File(type == 1 ? stopWordFilePath : hotWordFilePath);
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            log.error("hot word load failed: ",e.getMessage());
        }
        // TODO 优化读取文本内容的方法:不受int长度的显示
        byte[] buffer = new byte[(int)file.length()];
        long lastModified = file.lastModified();
        String etag = '"' + Long.toHexString(lastModified) + '-' + Long.toHexString(buffer.length) + '"';
        response.setHeader("Last-Modified",String.valueOf(lastModified));
        response.setHeader("ETag",etag);
        response.setContentType("text/plain;charset=utf-8");
        int offset = 0;
        if(fis != null){
            try{
                while (fis.read(buffer,offset,buffer.length-offset) != -1){}
            }catch (IOException e){
                e.printStackTrace();
                log.error("hot word read failed: ",e.getMessage());
            }finally {
                fis.close();
            }
        }
        OutputStream out = response.getOutputStream();
        out.write(buffer);
        out.flush();
    }
}

3、修改ik分词器配置文件IKAnalyzer.cfg.xml

<properties>
        <comment>IK Analyzer 扩展配置</comment>
        <!--用户可以在这里配置自己的扩展字典 -->
        <entry key="ext_dict">custom/my_extend.dic</entry>
         <!--用户可以在这里配置自己的扩展停止词字典-->
        <entry key="ext_stopwords"></entry>
        <!--用户可以在这里配置远程扩展字典 -->
        <entry key="remote_ext_dict">http://192.168.101.109:8080/hot/updateHotWord?type=0</entry>
        <!--用户可以在这里配置远程扩展停止词字典-->
         <entry key="remote_ext_stopwords">http://192.168.101.109:8080/hot/updateHotWord?type=1</entry>
</properties> 

4、重启es
会发现启动时会显示读取的分词内容
在这里插入图片描述
5、测试

GET _analyze
{
  "analyzer": "ik_smart",
  "text": ["这个是来自贵州贵阳的伍55的无敌尊贵氪金版iphone"]
}

结果

分词与分词库中设置的一致,停止词也被过滤了。测试通过

在这里插入图片描述
6、修改热词
extend.dic 中去掉了最后一条分词

伍55
伍Benjamin
贵州贵阳
爽爽的贵阳 

stop.dic中新增了“伍55”停止词

那个
那些
的
这些
这个
是
不是
伍55

修改后日志也会输出读取到的文本内容
在这里插入图片描述
7、测试

GET _analyze
{
  "analyzer": "ik_smart",
  "text": ["这个是来自贵州贵阳的伍55的无敌尊贵氪金版iphone"]
}

结果:此次的结果就没有“无敌尊贵氪金版iphone”分词了,“伍55”也被过滤了,测试通过!
在这里插入图片描述

2. 基于API的方式的优缺点

优点:上手简单

缺点:
(1)词库的管理不方便,要直接操作磁盘文件,检索页很麻烦
(2)文件的读写没有专门的优化,性能不好
(3)多一次接口调用和网络传输

下一期讲解如何通过修改IK源码的方式来实现基于数据库的热更新

3. 参考博客

【1】https://stackoverflow.com/questions/4533/http-generating-etag-header
【2】https://q.shanyue.tech/base/http/112.html

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
目录
相关文章
|
2月前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
60 4
|
26天前
|
自然语言处理 API
分词提取[关键词提取]免费API接口教程
接口用于从指定文本中提取关键词,支持POST和GET请求。需提供用户ID、用户KEY及待提取文本,可选设置关键词分隔符。返回状态码及结果或错误信息。示例中ID与KEY为公共测试用,建议使用个人ID与KEY以获得更高调用频率。
|
4月前
|
前端开发 API 网络架构
【Azure 应用服务】能否通过 Authentication 模块配置 Azure AD 保护 API 应用?
【Azure 应用服务】能否通过 Authentication 模块配置 Azure AD 保护 API 应用?
|
4月前
|
安全 API 网络安全
【Azure API 管理】APIM如何配置客户端证书的CRL检测策略
【Azure API 管理】APIM如何配置客户端证书的CRL检测策略
|
5月前
|
API 数据库 数据安全/隐私保护
Django配置api、管理系统和视图
Django配置api、管理系统和视图
131 1
|
5月前
|
API
zookeeper 使用api 进行节点增删改查及实现简易的配置中心
zookeeper 使用api 进行节点增删改查及实现简易的配置中心
53 2
|
4月前
|
JSON 算法 API
【Azure API 管理】APIM 配置Validate-JWT策略,验证RS256非对称(公钥/私钥)加密的Token
【Azure API 管理】APIM 配置Validate-JWT策略,验证RS256非对称(公钥/私钥)加密的Token
|
4月前
|
API
【Azure 环境】在Azure活动目录中的应用注册,给应用添加API权限时发现API权限配置缺失
【Azure 环境】在Azure活动目录中的应用注册,给应用添加API权限时发现API权限配置缺失
|
4月前
|
前端开发 API
【API管理 APIM】APIM中如何配置使用URL路径的方式传递参数(如由test.htm?name=xxx 变为test\xxx)
【API管理 APIM】APIM中如何配置使用URL路径的方式传递参数(如由test.htm?name=xxx 变为test\xxx)
|
4月前
|
应用服务中间件 Linux API
Linux 利用 Cloudflare API 配置 acme.sh 自动续签 SSL (Apache、Nginx适用)
安装acme.sh工具,命令为`curl https://get.acme.sh | sh -s email=你的邮箱`。接着配置Cloudflare API,创建并记录API令牌及Zone ID。最后通过`acme.sh --issue -d 你的域名 --dns dns_cf`签发SSL证书,对于Nginx可使用`acme.sh --install-cert`命令安装证书,并设置自动重载Nginx服务。