搜索系统 基础教程

搜索 query 分析

搜索系统 索引教程

搜索系统 高级教程

搜索系统 排序层

搜索系统 笔记

original icon
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.knowledgedict.com/tutorial/search-build-thread-safe-ik.html

如何线上搭建线程安全且高可用的 ik 分词器

搜索系统 笔记 搜索系统 笔记


ik 分词器是 java 编写的,它是字典树结构存储的基于词表的分词器,简单便捷及高效,常用于分词操作,那如何在搜索系统中,用 ik 来在线上搭建线程安全且高可用的 ik 分词器。

构建方式

要先明确的是,ik 分词器的 IKAnalyzer 类是线程不安全的,它在分词过程中的很多中间数据或中间变量存放在对象里,线程不安全。

引入 jar 包

首先引入 ik 相关 jar 包,可以根据不同的 lucene 版本,选择相应的版本,具体如下:

<!-- https://mvnrepository.com/artifact/com.jianggujin/IKAnalyzer-lucene -->
<dependency>
    <groupId>com.jianggujin</groupId>
    <artifactId>IKAnalyzer-lucene</artifactId>
    <version>7.0.0</version>
</dependency>

构建线程安全包装类

如上所述,IKAnalyzer 线程不安全,那我们给每个服务线程(指的是每个请求对应线程)创建 IKAnalyzer 对象,把其放在 ThreadLocal 局部变量里,这样每个请求都对应一个 IKAnalyzer 对象,这样就不会并发导致的线程安全问题了。

这里给出基于 spring 的 ik 分词器封装组件,具体代码如下:

import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import org.wltea.analyzer.lucene.IKAnalyzer;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * IKAnalyzer 组件
 **/
@Component("ikAnalyzer")
public class IKAnalyzerManager implements InitializingBean {

    private ThreadLocal<IKAnalyzer> ikAnalyzerThreadLocal = ThreadLocal.withInitial(() -> new IKAnalyzer(true));

    @Override
    public void afterPropertiesSet() throws Exception {

        /**
         * 这里初始化一个 IKAnalyzer 对象是为了服务启动时,加载 ik 的一些全局信息,防止第一次调用时非常慢
         */
        Analyzer analyzer = new IKAnalyzer(true);
        TokenStream ts = analyzer.tokenStream("", "初始化 IK 的字典");
        CharTermAttribute term = ts.getAttribute(CharTermAttribute.class);
        ts.reset();

        try {
            while (ts.incrementToken()) {
                log.info("init ik dictionary, {}|", term.toString());
            }
            if (ts != null) {
                ts.close();
            }
        } catch (IOException e) {
            log.error("IKAnalyzerComponent init error", e);
        } finally {
            analyzer.close();
        }
       
    }

    /**
     * 分词操作
     */
    public List<String> tokenize(String queryStr) {
        List<String> termList = new ArrayList<>();
        if (StringUtils.isBlank(queryStr)) {
            return termList;
        }
        IKAnalyzer analyzer = ikAnalyzerThreadLocal.get();
        TokenStream ts = analyzer.tokenStream("", queryStr);
        CharTermAttribute term = ts.getAttribute(CharTermAttribute.class);
        try {
            ts.reset();
            // 遍历分词数据
            while (ts.incrementToken()) {
                termList.add(term.toString());
            }
            if (ts != null) {
                ts.close();
            }
        } catch (IOException e) {
            log.error("IKAnalyzerComponent tokenize {} error", queryStr, e);
        } finally {

        }
        return termList;
    }

}

 

Elasticsearch是一个分布式、实时的搜索和分析引擎,被广泛用于构建高性能、可扩展的搜索和分析应用。复制分片策略:Elasticse ...
在介绍在各种系统中如何搭建 Java 开发环境之前,要明确几个 Java 环境相关的概念,一个是 JDK,另一个是 JRE。 ...
HanLP 是一系列模型与算法组成的 NLP 工具包,目标是普及自然语言处理在生产环境中的应用。HanLP 具备功能完善、性能高效、架构清晰 ...
当您使用Django搭建网站时,以下是基本的步骤流程,我将为您提供每个步骤的详细说明,并结合示例代码进行描述:步骤1:安装Django首先, ...
Flask 是基于 Python 编写的,所以安装 Flask 之前,要确保 Python 环境的安装。Python 从 3.4 版本开始就 ...