从 01 开始 从 01 开始
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 新闻合订本
    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档

晓林

程序猿,自由职业者,博主,英语爱好者,健身达人
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 新闻合订本
    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档
  • JavaSE

  • JavaSenior

  • JavaEE

  • JavaWeb

  • Spring

  • 主流框架

    • Redis

    • Mybatis

    • Lucene

      • 全文检索的概念
      • Lucene 概述
      • Lucene 入门案例
      • 分析器
        • 什么是分析器
        • 使用分析器
        • 标准分析器和中文
        • 中文分析器 IKAnalyzer
        • 自定义词典
        • 使用中文分析器创建索引
        • 源码
      • 常见的 Field
      • 索引库的维护
      • Lucene 索引库查询
    • Elasticsearch

    • MQ

    • MyCat

    • Lombok

  • SpringMVC

  • SpringBoot

  • Java
  • 主流框架
  • Lucene
2023-05-16
目录

分析器

# 30.分析器

接下来我们讲一个我们略过的重要的对象:分析器 ‍

# 什么是分析器

作用:即分析文档,去除停用词和标点符号等。默认使用的是标准分析器 StandardAnalyzer。 ‍ 我们之前构造索引的时候,使用的是默认配置 IndexWriterConfig:

IndexWriter indexWriter = new IndexWriter(directory, new IndexWriterConfig());
1

查看 IndexWriterConfig类 的源码,构造方法是这样的:默认使用 StandardAnalyzer

public IndexWriterConfig() {
    this(new StandardAnalyzer());
}
1
2
3

‍ 标准分析器,对英文的原始文档是没有问题的,怎么看有没问题呢?首先我们得会查看分析器的分析效果:

  • 首先 StandardAnalyzer 继承了 Analyzer,抽象类。所有分析器的类都继承了它
  • 使用 Analyzer 对象的 tokenStream 方法返回一个 Tokenstream 对象。该对象中包含了最终分词结果 ‍

# 使用分析器

所以我们想查看分析效果,直接使用并查看即可。实现步骤:

  1. 创建一个 Analyzer 对象,这里我们使用 StandardAnalyzer 对象
  2. 使用分析器对象的 tokenStream 方法获得一个 TokenStream 对象
  3. 向 TokenStream 对象中设置一个引用,相当于是一个指针。TokenStream 对象包含了所有关键词,类似链表一样排列着,我们用一个指针指向关键词,访问指针就相当于访问关键词
  4. 调用 TokenStream 对象的 rest 方法,用处是将指针指向第一个数据(如果不调用会抛异常)
  5. 使用 while 循环遍历 TokenStream 对象
  6. 关闭 TokenStream ‍ 代码如下:这里我们直接指定一段文本给分析器分析。
@Test
public void testTokenSteam() throws Exception {
    // 1. 创建一个Analyzer对象,这里我们使用StandardAnalyzer对象
    Analyzer analyzer = new StandardAnalyzer();

    // 2. 使用分析器对象的tokenStream方法获得一个TokenStream对象
    TokenStream tokenStream = analyzer.tokenStream("", "The Spring Framework provides a comprehensive programming and configuration model.");

    // 3. 向TokenStream对象中设置一个引用,相当于是一个指针。TokenStream对象包含了所有关键词,类似链表一样排列着,我们用一个指针指向关键词,访问指针就相当于访问关键词
    CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);

    // 4. 调用TokenStream对象的rest方法,用处是将指针指向第一个数据(如果不调用会抛异常)
    tokenStream.reset();

    // 5. 使用while循环遍历TokenStream对象
    while (tokenStream.incrementToken()) {  //返回true说明有下一个元素
        System.out.println(charTermAttribute.toString());
    }

    // 6. 关闭TokenStream
    tokenStream.close();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

‍ analyzer.tokenStream() 方法的第一个参数是 Field,由于我们是直接给定文本,这里就留空。运行结果:可以看到去除了 the,a 等单词和标点符号

spring
framework
provides
comprehensive
programming
configuration
model
1
2
3
4
5
6
7

# 标准分析器和中文

使用标准分析器,分析英文是没什么问题的;那如果是中文呢?我们可以测试下:

TokenStream tokenStream = analyzer.tokenStream("name", "鲁镇的酒店的格局,是和别处不同的:都是当街一个曲尺形的大柜台,柜里面预备着热水,可以随时温酒。做工的人,傍午傍晚散了工,每每花四文铜钱,买一碗酒,——这是二十多年前的事,现在每碗要涨到十文,——靠柜外站着,热热的喝了休息;倘肯多花一文,便可以买一碟盐煮笋,或者茴香豆,做下酒物了,如果出到十几文,那就能买一样荤菜,但这些顾客,多是短衣帮⑴,大抵没有这样阔绰⑵。只有穿长衫的,才踱进店面隔壁的房子里,要酒要菜,慢慢地坐喝。");
1

‍ 运行结果:一个汉字一行,说明一个关键字就是一行,这肯定是不行的。搜索一个汉字可以搜索得到,但搜索词语的话肯定是不能成功的。

‍

我们可以验证下,比如我们的原始文档“全文检索.txt”中,有“全文”这个词语,试试能不能搜索成功。我们修改 searchIndex 方法中的关键词:

    Query query = new TermQuery(new Term("content", "全文"));
1

‍ 运行结果:这是因为一个汉字一个关键字

查询出来的总记录数:0
1

‍ 所以标准分析器,在分词中文的时候,是不准确的,我们搜索一般都是输入关键词来搜索。为此我们使用中文分析器。

# 中文分析器 IKAnalyzer

虽然 Lucene 自带了一个中文分析器 SmartChineseAnalyzer,对中文支持较好,但扩展性差,扩展词库,禁用词库和同义词库等不好处理。

IK-Analyzer 不是官方提供的,而是第三方提供的。我们配置 3 个文件:

  • IKAnalyzer.cfg.xml:配置文件
  • hotword.dic:扩展词典,里面就是一些中文词语。可以添加一些新词,例如新出现的网络新词,新出现的公司名等
  • stopword.dic:停用词词典,无意义的词,或者敏感词

配置文件可以去我的 Gitee (opens new window) 或 GitHub (opens new window) 上下载。 ‍ 使用方法:

  • 添加依赖

    <dependency>
      <groupId>com.jianggujin</groupId>
      <artifactId>IKAnalyzer-lucene</artifactId>
      <version>7.0.0</version>
    </dependency>
    
    1
    2
    3
    4
    5
  • 添加配置文件、扩展词典和停用词词典,到 resources 目录下

  • 注意:hotword.dic 和 ext_stopword.dic 文件的格式为 UTF-8,注意是无 BOM 的 UTF-8 编码,否则报错。也就是说禁止使用 windows 记事本编辑扩展词典文件,该记事本默认是会保存为 UTF-8 BOM

  • 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">hotword.dic;</entry>
    
    	<!--用户可以在这里配置自己的扩展停止词字典-->
    	<entry key="ext_stopwords">stopword.dic;</entry> 
    
    </properties>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

测试:关键是第 4 行,创建的是 IKAnalyzer

@Test
public void testIKAnalyzer() throws Exception{
    // 1. 创建一个Analyzer对象,这里我们使用StandardAnalyzer对象
    Analyzer analyzer = new IKAnalyzer();

    // 2. 使用分析器对象的tokenStream方法获得一个TokenStream对象
    TokenStream tokenStream = analyzer.tokenStream("", "鲁镇的酒店的格局,是和别处不同的:都是当街一个曲尺形的大柜台,柜里面预备着热水,可以随时温酒。做工的人,傍午傍晚散了工,每每花四文铜钱,买一碗酒,——这是二十多年前的事,现在每碗要涨到十文,——靠柜外站着,热热的喝了休息;倘肯多花一文,便可以买一碟盐煮笋,或者茴香豆,做下酒物了,如果出到十几文,那就能买一样荤菜,但这些顾客,多是短衣帮⑴,大抵没有这样阔绰⑵。只有穿长衫的,才踱进店面隔壁的房子里,要酒要菜,慢慢地坐喝。");

    // 3. 向TokenStream对象中设置一个引用,相当于是一个指针。TokenStream对象包含了所有关键词,类似链表一样排列着,我们用一个指针指向关键词,访问指针就相当于访问关键词
    CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);

    // 4. 调用TokenStream对象的rest方法,用处是将指针指向第一个数据(如果不调用会抛异常)
    tokenStream.reset();

    // 5. 使用while循环遍历TokenStream对象
    while (tokenStream.incrementToken()) {  //返回true说明有下一个元素
        System.out.println(charTermAttribute.toString());
    }

    // 6. 关闭TokenStream
    tokenStream.close();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

‍ 部分运行结果:可以看到是有一些词语的,并且显示加载了两个词典。

‍

IKAnalyzer 是一个开源的,基于 java 语言开发的轻量级的中文分词工具包,由国人 林良益 (opens new window) 先生开发,从 2006 年 12 月推出 1.0 版开始。由于林良益先生在 2012 之后未对 IKAnalyzer 进行更新,后续版本的 Lucene 分词接口发生变化,导致不能在 Lucene 中使用了。

因此我们用的是这个分析器:IKAnalyzer-lucene (opens new window),是基于 IKAnalyzer 做了兼容性处理的。 ‍

# 自定义词典

有时候我们需要添加一些流行语,此时词典是没有的,那么分词就会失败。例如:

我们加上了一个流行语“鸡你太美”,但是分词后将其分成了 3 部分“鸡”,“你”,“太美”,我们可以在 hotword.dic 中添加这个流行词,然后就能看到正常分词了:

‍

停用词同理,这里就不演示了。

# 使用中文分析器创建索引

之前我们说过,创建索引时默认使用的是标准分析器,我们可以自定义使用什么分析器,只需在构造函数里指定即可,代码如下:

@Test
    public void createIndexWithIK() throws Exception {
        //  1. 创建一个Director对象,指定索引库保存的位置。
        Directory directory = FSDirectory.open(new File("D:\\temp\\index").toPath());

        IndexWriterConfig config = new IndexWriterConfig(new IKAnalyzer());
        //  2. 基于Directory对象创建一个IndexWriter对象(用来写索引)
        IndexWriter indexWriter = new IndexWriter(directory, config);

        //  3. 读取磁盘上的文件,对应每个文件创建一个文档对象。
        File dir = new File("D:\\temp\\searchsource");
        File[] files = dir.listFiles();
        for (File file : files) {
            String fileName = file.getName();
            String filePath = file.getPath();
            String fileContent = FileUtils.readFileToString(file, "utf-8");
            long fileSize = FileUtils.sizeOf(file);

            // 4. 创建Field
            // 参数1:域的名称, 参数2:域的内容, 参数3:是否存储
            Field fieldName = new TextField("name", fileName, Field.Store.YES);
            Field fieldPath = new TextField("path", filePath, Field.Store.YES);
            Field fieldContent = new TextField("content", fileContent, Field.Store.YES);
            Field fieldSize = new TextField("size", String.valueOf(fileSize), Field.Store.YES);

            // 4. 将field添加到document对象中。
            Document document = new Document();
            document.add(fieldName);
            document.add(fieldPath);
            document.add(fieldContent);
            document.add(fieldSize);

            //  5. 使用IndexWriter对象将document对象写入索引库,此过程进行索引创建,并将索引和document对象写入索引库。
            indexWriter.addDocument(document);
        }

        //  6. 关闭IndexWriter对象。
        indexWriter.close();
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

我们先将之前的索引库删掉,然后运行该测试方法,并用 Luke 重新打开:可以看到有中文的词语了。而使用标准分析器,中文都是一个一个字的

‍

# 源码

已将源码上传到 Gitee (opens new window) 或 GitHub (opens new window) 上。并且创建了分支 demo2IK,读者可以通过切换分支来查看本文的示例代码

上次更新: 2025/5/17 12:26:09
Lucene 入门案例
常见的 Field

← Lucene 入门案例 常见的 Field→

最近更新
01
新闻合订本 2025-10
10-31
02
2025 年 10 月记
10-30
03
用 AI 批量优化思源笔记排版
10-15
更多文章>
Theme by Vdoing | Copyright © 2022-2025 | 粤 ICP 备 2022067627 号 -1 | 粤公网安备 44011302003646 号 | 点击查看十年之约
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式