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加载配置文件值

elasticsearch ik分词器远程扩展词典放nginx服务器实现热更新不需重启es_第1张图片

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

elasticsearch ik分词器远程扩展词典放nginx服务器实现热更新不需重启es_第2张图片

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

elasticsearch ik分词器远程扩展词典放nginx服务器实现热更新不需重启es_第3张图片

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是有大厨小炒 切分成大厨和小炒两个词

elasticsearch ik分词器远程扩展词典放nginx服务器实现热更新不需重启es_第4张图片

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下,如:

elasticsearch ik分词器远程扩展词典放nginx服务器实现热更新不需重启es_第5张图片

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

4.在es的ik分词器中配置文件 IKAnalyzer.cfg.xml配置远程扩展词典路径:




        IK Analyzer 扩展配置
        
        
         
        
        
        http://192.168.25.128/mydict.dic
        
        

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

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

elasticsearch ik分词器远程扩展词典放nginx服务器实现热更新不需重启es_第6张图片

你可能感兴趣的:(elasticsearch ik分词器远程扩展词典放nginx服务器实现热更新不需重启es)