elasticsearch ik分词器远程扩展词典放nginx服务器实现热更新不需重启es

一、前提准备

(1)elasticsearch集群,且都装有ik分词器

ik分词器安装参看下:https://blog.csdn.net/chen_2890/article/details/83757022 

(2)安装有nginx作为静态资源服务器(使用这种方式需依赖nginx通过http访问,依赖于网络和nginx的稳定,可以采用修改Ik分词器原来,通过从mysql中获取分词数据)

二、分析ik分词器源码

ik分词器源码地址:https://github.com/medcl/elasticsearch-analysis-ik/tree/v5.2.0

1.获取ik中配置文件 IKAnalyzer.cfg.xml  Properties props加载配置文件值

2. 开启远程词典时,查找配置的远程词典文件路径,从prop属性中查找出remote_ext_dict 配置项的值,处理成文件路径列表

3.每个远程词典文件开启一个监控线程,进行监控,每60秒调度一次,运行Monitor 里的run方法

4.run方法里访问远程词典,保存上一次的Last-Modified 根据响应的上次修改时间与保存的上次修改时间判断远程文件是否变化,变化的话重新加载远程文件。

/**
	 * 监控流程:
	 *  ①向词库服务器发送Head请求
	 *  ②从响应中获取Last-Modify、ETags字段值,判断是否变化
	 *  ③如果未变化,休眠1min,返回第①步
	 * 	④如果有变化,重新加载词典
	 *  ⑤休眠1min,返回第①步
	 */

	public void run() {

		//超时设置
		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,eTags
					Dictionary.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);
			}
		}
	}

 

三、实现步骤

1.创建es索引,添加mapping,给字段添加ik分词器配置

  private static TransportClient client;

    static {
        try{
            // 1 设置连接的集群名称
            Settings settings = Settings.builder().put("cluster.name", "MYELK").build();
            // 2 连接集群
            client = new PreBuiltTransportClient(settings);
            client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("ELK05"), 9300));
        }catch (Exception e){
        }
    }

    /**
        * @Description: 创建索引
      * @author tang
      * @date 2019/2/6 14:53
      */
    public static void createIndex(String indexNames,String type) throws Exception{

        XContentBuilder mapping = createMapping(indexNames, type);
        // 1 创建索引.
        CreateIndexRequestBuilder indexRequestBuilder = client.admin().indices().prepareCreate(indexNames).addMapping(type,mapping);
        indexRequestBuilder.get();

    }
  
    /**
        * @Description: 创建mapping 并配置分词器
      * @author tang
      * @date 2019/3/9 19:39
      */
    public static void addMapping(String index,String type) throws Exception {

        // 1设置mapping
        XContentBuilder builder = XContentFactory.jsonBuilder()
                .startObject()
                .startObject(type)
                .startObject("properties")
                .startObject("spu_name")
                .field("type", "text")
                .field("analyzer", "ik_max_word")
                .field("search_analyzer","ik_smart")
                .endObject()
                .startObject("shop_name")
                .field("type", "text")
                .field("analyzer", "ik_max_word")
                .field("search_analyzer","ik_smart")
                .endObject()
                .endObject()
                .endObject()
                .endObject();

        // 2 添加mapping
        PutMappingRequest mapping = Requests.putMappingRequest(index).type(type).source(builder);

        client.admin().indices().putMapping(mapping).get();

        // 3 关闭资源
        client.close();
    }

   public static void main(String[] args) throws Exception{
        
      createIndex("item","2020-03-25");
      //给index的type添加mapping,需要先创建索引先
      addMapping("item","2020-03-28");
      
    }

2.搜索内容:大厨小炒 名中 大厨和小炒两个词,说明es是有大厨小炒 切分成大厨和小炒两个词

3.在nginx上添加ik分词扩展词典

nginx配置:

 server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }
    }

把远程字典放在 nginx 跟目录 html下,如:

在谷歌浏览器上输入地址 :http://192.168.25.128/mydict.dic  检查是否能下载此文件

4.在es的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"></entry>
         <!--用户可以在这里配置自己的扩展停止词字典-->
        <entry key="ext_stopwords"></entry>
        <!--用户可以在这里配置远程扩展字典 -->
        <entry key="remote_ext_dict">http://192.168.25.128/mydict.dic</entry>
        <!--用户可以在这里配置远程扩展停止词字典-->
        <!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>

5.把词语:大厨小炒  放到远程词典中,直接修改或覆盖ngix上的mydict.dic文件,ik分词器检查到远程文件有变化,则重新加载远程文件,不需要重启es服务器

6.再次搜索 大厨小炒 搜发现直接命中 大厨小炒 这一整个词,说明es是按 大厨、小炒、大厨小炒 来切分成三个单词了。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值