ES 十月 12, 2021

分词器

文章字数 6k 阅读约需 5 mins. 阅读次数 0

分词器

规范化 normalization

字符过滤器 character filter

分词之前的预处理,过滤无用字符

分词器 tokenizer

切词用

常见的分词器

  • standard analyzer:默认分词器,中文支持的不理想,会逐字拆分。
  • pattern tokenizer:以正则匹配分隔符,把文本拆分成若干词项。
  • simple pattern tokenizer:以正则匹配词项,速度比pattern tokenizer快。
  • whitespace analyzer:以空白符分隔

中文分词器 ik

安装与部署

ik主要文件

  • 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">words_location</entry> -->
        <!--用户可以在这里配置远程扩展停止词字典-->
        <!-- <entry key="remote_ext_stopwords">words_location</entry> -->
    </properties>
    
  • 字典 同目录下的dic文件

    • 主词库 main.dic
    • 停用词库 stopword.dic
    • 计量单位词库 quantifier.dic
    • 行政单位词库 suffix.dic
    • 姓氏词库 surname.dic
    • 语气词库 preposition.dic
    • 扩展词库 extra_*.dic

不同类别的analyzer

  • ik_max_word: 将文本做最细粒度的拆分,会穷尽各种可能的组合,适合 Term Query;
  • ik_smart: 会做最粗粒度的拆分,适合 Phrase 查询。

eg:

post localhost:9200/_analyze{
    {“text”:“中华人民共和国人民大会堂”,“analyzer”:“ik_max_word” }
}

热更新

接口更新:
  • 通过编写符合规范的自定义的接口配置到ik配置文件的远程扩展字典位置 remote_ext_dict

规范: 一个utf-8编码格式的txt文件,

​ 请求头中包含Last-ModifiedETag 来确认字典更新.

通过mysql热更新.需要修改ik分词器源码.

org.wltea.analyzer.dic.Dictionary#loadMainDict方法里添加自定义的远程词库

/**
 * 加载主词典及扩展词典
 */
private void loadMainDict() {
   // 建立一个主词典实例
   _MainDict = new DictSegment((char) 0);

   // 读取主词典文件
   Path file = PathUtils.get(getDictRoot(), Dictionary.PATH_DIC_MAIN);
   loadDictFile(_MainDict, file, false, "Main Dict");
   // 加载扩展词典
   this.loadExtDict();
   // 加载远程自定义词库
   this.loadRemoteExtDict();

   // 加载远程自定义词库
   this.loadMySQLExtDict();
}
/**
     * 从mysql加载热更新词典
     */
    private void loadMySQLExtDict() {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;

        try {
            Path file = PathUtils.get(getDictRoot(), "jdbc-reload.properties");
            prop.load(new FileInputStream(file.toFile()));
            logger.info("jdbc-reload.properties");
            for(Object key : prop.keySet()) {
                logger.info("" + key + "=" + prop.getProperty(String.valueOf(key)));
            }
            logger.info(" hot dict " + prop.getProperty("jdbc.reload.sql") + "......");
            conn = DriverManager.getConnection(
                    prop.getProperty("jdbc.url"),
                    prop.getProperty("jdbc.user"),
                    prop.getProperty("jdbc.password"));
            stmt = conn.createStatement();
            rs = stmt.executeQuery(prop.getProperty("jdbc.reload.sql"));
            while(rs.next()) {
                String theWord = rs.getString("word");
                logger.info("hot word: " + theWord);
                _MainDict.fillSegment(theWord.trim().toCharArray());
            }
            Thread.sleep(Integer.valueOf(String.valueOf(prop.get("jdbc.reload.interval"))));
        } catch (Exception e) {
            logger.error("erorr", e);
        } finally {
            if(rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    logger.error("error", e);
                }
            }
            if(stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException e) {
                    logger.error("error", e);
                }
            }
            if(conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    logger.error("error", e);
                }
            }
        }
    }

停用词mysql扩展同理.

mvn package 打包,替换原来的jar包,并补充需要的mysql连接依赖包.

0%