Elasticsearch分词插件配置

2024-06-04 05:44

本文主要是介绍Elasticsearch分词插件配置,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

    • 1、 分词插件配置
          • 1.1、[IK分词器地址](https://github.com/infinilabs/analysis-ik/tree/v7.11.1?tab=readme-ov-file)
          • 1.2、分词器配置
    • 2、分词插件词库配置
      • 2.1、使用词库文件
      • 2.2、使用远程扩展词(官方推荐)
      • 2.3、自定义一个监控线程,从数据中加载
          • 2.3.1、新建监控线程:
          • 2.3.2、读取数据
          • 2.3.3、新建jdbc.properties文件
          • 2.3.4、新建表
          • 2.4 几种方式对比

前言: Elasticsearch是一个分布式、高扩展、高实时的搜索与数据分析引擎。通常情况下,会使用ES来存储商品、订单、商品评论等数据。

本篇文章主要讲一下es分词插件的配置,以及词库的更新。

1、 分词插件配置

ES本身是支持分词的,但是默认的分词针对中文不太友好,所以通常情况下,我们需要使用中文分词器,常见的分词器可以参考这篇文章:Elasticsearch 中文分词器

本篇文章介绍的是:IK 中文分词器

1.1、IK分词器地址
1.2、分词器配置

解压下载的压缩包,将文件夹名称改为ik,然后将整个文件夹放到plugins目录下,重启es就可以了
在这里插入图片描述

2、分词插件词库配置

至于为什么要自定义词库,可以参考下这篇文章 Elasticsearch自定义分词

自定义分词的常见几种配置

2.1、使用词库文件

在这里插入图片描述

2.2、使用远程扩展词(官方推荐)

这种方式远离是通过开启一个定时任务,60秒执行一次,从远程仓库查询,根据请求头中返回的参数判断是否更新词库

部分源码截图 Dictionary类

	public static synchronized void initial(Configuration cfg) {if (singleton == null) {synchronized (Dictionary.class) {if (singleton == null) {singleton = new Dictionary(cfg);singleton.loadMainDict();singleton.loadSurnameDict();singleton.loadQuantifierDict();singleton.loadSuffixDict();singleton.loadPrepDict();singleton.loadStopWordDict();if(cfg.isEnableRemoteDict()){// 建立监控线程for (String location : singleton.getRemoteExtDictionarys()) {// 10 秒是初始延迟可以修改的 60是间隔时间 单位秒pool.scheduleAtFixedRate(new Monitor(location), 10, 60, TimeUnit.SECONDS);}for (String location : singleton.getRemoteExtStopWordDictionarys()) {pool.scheduleAtFixedRate(new Monitor(location), 10, 60, TimeUnit.SECONDS);}}}
/*** 监控流程:*  ①向词库服务器发送Head请求*  ②从响应中获取Last-Modify、ETags字段值,判断是否变化*  ③如果未变化,休眠1min,返回第①步* 	④如果有变化,重新加载词典*  ⑤休眠1min,返回第①步*/public void runUnprivileged() {//超时设置RequestConfig rc = RequestConfig.custom().setConnectionRequestTimeout(10*1000).setConnectTimeout(10*1000).setSocketTimeout(15*1000).build();HttpHead head = new HttpHead(location);head.setConfig(rc);//设置请求头if (last_modified != null) {head.setHeader("If-Modified-Since", last_modified);}if (eTags != null) {head.setHeader("If-None-Match", eTags);}CloseableHttpResponse response = null;try {response = httpclient.execute(head);//返回200 才做操作if(response.getStatusLine().getStatusCode()==200){if (((response.getLastHeader("Last-Modified")!=null) && !response.getLastHeader("Last-Modified").getValue().equalsIgnoreCase(last_modified))||((response.getLastHeader("ETag")!=null) && !response.getLastHeader("ETag").getValue().equalsIgnoreCase(eTags))) {// 远程词库有更新,需要重新加载词典,并修改last_modified,eTagsDictionary.getSingleton().reLoadMainDict();last_modified = response.getLastHeader("Last-Modified")==null?null:response.getLastHeader("Last-Modified").getValue();eTags = response.getLastHeader("ETag")==null?null:response.getLastHeader("ETag").getValue();}}else if (response.getStatusLine().getStatusCode()==304) {//没有修改,不做操作//noop}else{logger.info("remote_ext_dict {} return bad code {}" , location , response.getStatusLine().getStatusCode() );}} catch (Exception e) {logger.error("remote_ext_dict {} error!",e , location);}finally{try {if (response != null) {response.close();}} catch (IOException e) {logger.error(e.getMessage(), e);}}}}

在这里插入图片描述

2.3、自定义一个监控线程,从数据中加载

部分代码:

2.3.1、新建监控线程:
/*** 词典初始化 由于IK Analyzer的词典采用Dictionary类的静态方法进行词典初始化* 只有当Dictionary类被实际调用时,才会开始载入词典, 这将延长首次分词操作的时间 该方法提供了一个在应用加载阶段就初始化字典的手段* * @return Dictionary*/public static synchronized void initial(Configuration cfg) {if (singleton == null) {synchronized (Dictionary.class) {if (singleton == null) {singleton = new Dictionary(cfg);singleton.loadMainDict();singleton.loadSurnameDict();singleton.loadQuantifierDict();singleton.loadSuffixDict();singleton.loadPrepDict();singleton.loadStopWordDict();if(cfg.isEnableRemoteDict()){// 建立监控线程for (String location : singleton.getRemoteExtDictionarys()) {// 10 秒是初始延迟可以修改的 60是间隔时间 单位秒pool.scheduleAtFixedRate(new Monitor(location), 10, 60, TimeUnit.SECONDS);}for (String location : singleton.getRemoteExtStopWordDictionarys()) {pool.scheduleAtFixedRate(new Monitor(location), 10, 60, TimeUnit.SECONDS);}}// 建立数据库监控线程pool.scheduleAtFixedRate(new DatabaseMonitor(), 10, Long.parseLong(getSingleton().getProperty(DatabaseMonitor.JDBC_UPDATE_INTERVAL)), TimeUnit.SECONDS);}}}}/*** 加载新词条*/public static void addWord(String word) {singleton._MainDict.fillSegment(word.trim().toLowerCase().toCharArray());}/*** 移除(屏蔽)词条*/public static void disableWord(String word) {singleton._MainDict.disableSegment(word.trim().toLowerCase().toCharArray());}/*** 加载 jdbc.properties*/public void loadJdbcProperties() {Path file = PathUtils.get(getDictRoot(), DatabaseMonitor.PATH_JDBC_PROPERTIES);try {props.load(Files.newInputStream(file.toFile().toPath()));logger.info("====================================jdbc配置文件内容 start====================================");for (Map.Entry<Object, Object> entry : props.entrySet()) {logger.info("key:{} value:{}", entry.getKey(), entry.getValue());}logger.info("====================================jdbc配置文件内容 end====================================");} catch (IOException e) {logger.error("加载jdbc属性配置文件失败 文件名称:{} exMsg:{}",DatabaseMonitor.PATH_JDBC_PROPERTIES,e.getMessage(),e);}
2.3.2、读取数据
public class DatabaseMonitor implements Runnable {private static final Logger logger = ESPluginLoggerFactory.getLogger(DatabaseMonitor.class.getName());public static final String PATH_JDBC_PROPERTIES = "jdbc.properties";private static final String JDBC_URL = "jdbc.url";private static final String JDBC_USERNAME = "jdbc.username";private static final String JDBC_PASSWORD = "jdbc.password";private static final String JDBC_DRIVER = "jdbc.driver";private static final String SQL_UPDATE_MAIN_DIC = "jdbc.update.main.dic.sql";/*** 更新间隔*/public final static  String JDBC_UPDATE_INTERVAL = "jdbc.update.interval";private static final Timestamp DEFAULT_LAST_UPDATE = Timestamp.valueOf(LocalDateTime.of(LocalDate.of(2020, 1, 1), LocalTime.MIN));private static Timestamp lastUpdateTimeOfMainDic = null;public String getUrl() {return Dictionary.getSingleton().getProperty(JDBC_URL);}public String getUsername() {return Dictionary.getSingleton().getProperty(JDBC_USERNAME);}public String getPassword() {return Dictionary.getSingleton().getProperty(JDBC_PASSWORD);}public String getDriver() {return Dictionary.getSingleton().getProperty(JDBC_DRIVER);}public String getUpdateMainDicSql() {return Dictionary.getSingleton().getProperty(SQL_UPDATE_MAIN_DIC);}/*** 加载MySQL驱动*/public DatabaseMonitor() {SpecialPermission.check();AccessController.doPrivileged((PrivilegedAction<Void>) () -> {try {Class.forName(getDriver());} catch (ClassNotFoundException e) {logger.error("mysql jdbc driver not found", e);}return null;});}@Overridepublic void run() {SpecialPermission.check();AccessController.doPrivileged((PrivilegedAction<Void>) () -> {// 更新主词典performMainDicUpdate();return null;});}public Connection getConnection() {Connection connection = null;try {connection = DriverManager.getConnection(getUrl(), getUsername(), getPassword());} catch (SQLException e) {logger.error("failed to get connection", e);}return connection;}public void closeConnection(Connection conn) {if (conn != null) {try {conn.close();} catch (SQLException e) {logger.error("failed to close Connection", e);}}}public void closeRsAndPs(ResultSet rs, PreparedStatement ps) {if (rs != null) {try {rs.close();} catch (SQLException e) {logger.error("failed to close ResultSet", e);}}if (ps != null) {try {ps.close();} catch (SQLException e) {logger.error("failed to close PreparedStatement", e);}}}/*** 执行主词典更新操作,根据返回结果决定是否继续查询*/public synchronized void performMainDicUpdate() {Connection conn = getConnection();boolean continueQuery = true;while (continueQuery) {continueQuery = updateMainDic(conn);if (!continueQuery) {logger.info("数据处理完毕!");}}closeConnection(conn);}/*** 更新主词典数据* @param conn 数据库连接* @return 是否有新数据返回*/public boolean updateMainDic(Connection conn) {boolean newDataReturned = false;logger.info("开始更新主词汇库");int numberOfAddWords = 0;int numberOfDisableWords = 0;PreparedStatement ps = null;ResultSet rs = null;try {String sql = getUpdateMainDicSql();Timestamp param = lastUpdateTimeOfMainDic == null ? DEFAULT_LAST_UPDATE : lastUpdateTimeOfMainDic;logger.info("当前更新时间戳 param:{} ",param);ps = conn.prepareStatement(sql);ps.setTimestamp(1, param);rs = ps.executeQuery();while (rs.next()) {newDataReturned = true;String word = rs.getString("word");word = word.trim();if (word.isEmpty()) {continue;}lastUpdateTimeOfMainDic = rs.getTimestamp("updateTime");if (rs.getBoolean("isDeleted")) {// 删除Dictionary.disableWord(word);numberOfDisableWords++;} else {// 添加Dictionary.addWord(word);numberOfAddWords++;}}logger.info("更新主词汇完成 -> addWord: {}, disableWord: {}", numberOfAddWords, numberOfDisableWords);} catch (SQLException e) {newDataReturned = false;logger.error("更新主词汇失败 exMsg:{}",e.getMessage(),e);// 如果捕获到异常,将 lastUpdateTimeOfMainDic 的值减少一些if (lastUpdateTimeOfMainDic != null) {Calendar cal = Calendar.getInstance();cal.setTime(lastUpdateTimeOfMainDic);cal.add(Calendar.MINUTE, -1); // 将时间减少1分钟,可以根据实际需求调整lastUpdateTimeOfMainDic = new Timestamp(cal.getTime().getTime());}}finally {// 关闭 ResultSet、PreparedStatementcloseRsAndPs(rs, ps);}return newDataReturned;}
}
2.3.3、新建jdbc.properties文件
jdbc.url=
jdbc.username=
jdbc.password=
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.update.main.dic.sql=SELECT * FROM `cs_es_extra_main` WHERE updateTime > ? order by updateTime asc limit 1000
### 定时任务间隔时间
jdbc.update.interval=60
2.3.4、新建表
CREATE TABLE `cs_es_extra_main` (`id` bigint(20) NOT NULL COMMENT '主键',`word` varchar(255) NOT NULL COMMENT '词',`isDeleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否已删除',`updateTime` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) COMMENT '是否已删除 0:未删除 1:已删除',PRIMARY KEY (`id`),UNIQUE KEY `cs_es_extra_main_word_IDX` (`word`) USING BTREE,KEY `es_extra_main_updateTime_IDX` (`updateTime`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='es分词器主分词';
2.4 几种方式对比
  • 使用词库文件
    优点:这种配置方式比较简单
    缺点:但是更新复杂,每次更新需要重启ES(在生产情况下,这个不太现实)

  • 使用远程词库
    优点:更新比较方便,也不用重启ES
    缺点:更新有延时,而且数据量比较大的时候,会有一定影响

  • 自定义词库更新
    优点:更新方便,更新的数据量可配,而且是增量更新。
    缺点:需要对ik分词插件进行自定义修改

上面就是关于Elasticsearch分词插件配置,代码仅供参考学习,欢迎留言讨论。后续会将完整的项目代码更新到远程仓库,欢迎关注我的公众号,后续会在公众号提供获取地址。
在这里插入图片描述

这篇关于Elasticsearch分词插件配置的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Linux 安装、配置Tomcat 的HTTPS

Linux 安装 、配置Tomcat的HTTPS 安装Tomcat 这里选择的是 tomcat 10.X ,需要Java 11及更高版本 Binary Distributions ->Core->选择 tar.gz包 下载、上传到内网服务器 /opt 目录tar -xzf 解压将解压的根目录改名为 tomat-10 并移动到 /opt 下, 形成个人习惯的路径 /opt/tomcat-10

uniapp接入微信小程序原生代码配置方案(优化版)

uniapp项目需要把微信小程序原生语法的功能代码嵌套过来,无需把原生代码转换为uniapp,可以配置拷贝的方式集成过来 1、拷贝代码包到src目录 2、vue.config.js中配置原生代码包直接拷贝到编译目录中 3、pages.json中配置分包目录,原生入口组件的路径 4、manifest.json中配置分包,使用原生组件 5、需要把原生代码包里的页面修改成组件的方

IDEA配置Tomcat远程调试

因为不想把本地的Tomcat配置改乱或者多人开发项目想测试,本文主要是记录一下,IDEA使用Tomcat远程调试的配置过程,免得一段时间不去配置到时候忘记(毕竟这次是因为忘了,所以才打算记录的…) 首先在catalina.sh添加以下内容 JAVA_OPTS="-Dcom.sun.management.jmxremote=-Dcom.sun.management.jmxremote.port

Steam邮件推送内容有哪些?配置教程详解!

Steam邮件推送功能是否安全?如何个性化邮件推送内容? Steam作为全球最大的数字游戏分发平台之一,不仅提供了海量的游戏资源,还通过邮件推送为用户提供最新的游戏信息、促销活动和个性化推荐。AokSend将详细介绍Steam邮件推送的主要内容。 Steam邮件推送:促销优惠 每当平台举办大型促销活动,如夏季促销、冬季促销、黑色星期五等,用户都会收到邮件通知。这些邮件详细列出了打折游戏、

微信小程序开发必知必会:文件结构和基本配置

一、微信小程序基本文件结构 1.  project.config.json:项目的基本配置文件,包括项目名称、appid、项目目录、页面文件夹等。     {"setting": {"urlCheck": false,"es6": true,"postcss": true,"nodeModulesPath": "D:\\\\node_modules"},"appid": "wxd678e

【杂记-浅谈DHCP动态主机配置协议】

DHCP动态主机配置协议 一、DHCP概述1、定义2、作用3、报文类型 二、DHCP的工作原理三、DHCP服务器的配置和管理 一、DHCP概述 1、定义 DHCP,Dynamic Host Configuration Protocol,动态主机配置协议,是一种网络协议,主要用于在IP网络中自动分配和管理IP地址以及其他网络配置参数。 2、作用 DHCP允许计算机和其他设备通

WordPress网创自动采集并发布插件

网创教程:WordPress插件网创自动采集并发布 阅读更新:随机添加文章的阅读数量,购买数量,喜欢数量。 使用插件注意事项 如果遇到404错误,请先检查并调整网站的伪静态设置,这是最常见的问题。需要定制化服务,请随时联系我。 本次更新内容 我们进行了多项更新和优化,主要包括: 界面设置:用户现在可以更便捷地设置文章分类和发布金额。代码优化:改进了采集和发布代码,提高了插件的稳定

Pycharm配置conda环境(解决新版本无法识别可执行文件问题)

引言: 很多小伙伴在下载最新版本的pycharm或者更新到最新版本后为项目配置conda环境的时候,发现文件夹目录中无法显示可执行文件(一般为python.exe),以下就是本人遇到该问题后试验和解决该问题的一些方法和思路。 一般遇到该问题的人群有两种,一种是刚入门对pycharm进行conda环境配置的小白(例如我),不熟悉相关环境配置的操作和过程,还有一种是入坑pycharm有段时间的老手

vscode-创建vue3项目-修改暗黑主题-常见错误-element插件标签-用法涉及问题

文章目录 1.vscode创建运行编译vue3项目2.添加项目资源3.添加element-plus元素4.修改为暗黑主题4.1.在main.js主文件中引入暗黑样式4.2.添加自定义样式文件4.3.html页面html标签添加样式 5.常见错误5.1.未使用变量5.2.关闭typescript检查5.3.调试器支持5.4.允许未到达代码和未定义代码 6.element常用标签6.1.下拉列表

【zabbix】zabbix客户端配置

1、部署zabbix客户端 #zabbix 5.0 版本采用 golang 语言开发的新版本客户端 agent2 。#zabbix 服务端 zabbix_server 默认使用 10051 端口,客户端 zabbix_agent2 默认使用 10050 端口。systemctl disable --now firewalldsetenforce 0hostnamectl set-host