软件工程应用与实践(5)——词云的获取

2021SC@SDUSC

一、简介

经过小组分工和讨论后,决定由我负责分析词云的获取和整理的部分。在老年健康知识图谱系统中,词云图表示了知识图谱中出现的专业名词及其出现频率。
在这里插入图片描述

二、word文档分词

2.1 java引入jieba分词

引入依赖

本项目使用jieba分词对word文档中的文本实现分词,jieba-analysis库用于实现在java语言中进行jieba分词

<dependency>
  <groupId>com.huaban</groupId>
  <artifactId>jieba-analysis</artifactId>
  <version>1.0.2</version>
</dependency>

在引入jieba分词后,利用hutool工具中的TokenizerEngine完成中文分词,以下是一个小例子

//分词测试
@Test
public void testJieba(){
    TokenizerEngine engine = TokenizerUtil.createEngine();
    String text = "这是一句话";
    Result result = engine.parse(text);
    String resultStr = CollUtil.join((Iterator<Word>)result, " ");
    //这是 一句 话
    System.out.println(resultStr);
}

TokenizerEngine会根据用户引入的依赖自动判断使用哪个分词引擎,查阅hutool官网可知,目前hutool支持的分词有以下几种
在这里插入图片描述

2.2 读取word文档完成分词

上面的小例子是对一个简单的字符串进行中文分词,在本项目中需要对word文档进行分词,因此需要首先读取word文档,再对word文档进行分词

FileReader fileReader = new FileReader("filePath");
List<String> list = fileReader.readLines();
List<String> finalResult = new ArrayList<>();
list.forEach(l->{
	TokenizerEngine engine = TokenizerUtil.createEngine();
	String text = l;
	Result result = engine.parse(text);
    String resultStr = CollUtil.join((Iterator<Word>)result, " ");
    finalResult.add(resultStr)
})

三、词云的获取

在对word文档进行分词分词之后,由于word文档中有很多与医学无关的停用词,这一部分词不能显示到首页上,需要进行筛选,删除停用词后展示到首页。在本项目中,首先从文件中获取停用词,再对获取到的词语进行筛选。

3.1 获取所有词

本项目通过dao层访问数据库,服务层调用dao层接口,controller层调用服务层。mybatis完成dao层接口与sql语句的映射

保存词云的实体类

  • 使用lombok的@Data注解,当编译时自动为实体类添加get,set,equals,hashcode,toString方法
  • 使用lombok的@AllArgsConstructor注解,为类自动添加带参的构造方法
  • 使用lombok的@NoArgsConstructor注解,为类自动添加无参的构造方法
  • 使用lombok的@Accessors注解,可以实现链式调用
package com.sdu.nurse.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class WordCloudData
{
    //词云名称
    private String name;
    //词云数据
    private Integer value;
}

延伸说明:链式调用的进一步解释

当我们平时使用实体类,为实体类赋值时,需要反复调用set方法。假设我们有一个User类,里面有name,age,id三个属性,我们需要分别调用三次set方法

User user = new User();
user.setName("name");
user.setAge(20);
user.setId("id");

由于普通set方法的返回值是void,因此无法实现链式调用。在lombok中,使用@Accessors(chain = true)注解可以使set方法返回本对象,因此使用链式调用可以简化操作,不需要重复写多个set语句,仅需在一个语句中重复调用set方法即可

User user = new User();
user.setName("name").setAge(20).setId("id");

dao层接口

dao接口中的getWordCloudData()方法完成词云图的获取

package com.sdu.nurse.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.sdu.nurse.entity.WordCloudData;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface WordCloudDataDao extends BaseMapper<WordCloudData>
{
    List<WordCloudData> getWordCloudData();
}

mysql中的正则匹配

在使用sql语句从数据库中获取词云的过程中,需要排除非中文字符,本项目中使用mysql中的

REGEXP '[\u4e00-\u9fa5]'

函数用于匹配中文字符

3.2 去除停用词

在本项目中,在service层去除停用词,停用词保存在一个文件中,通过hutool的FileReader类按行获取停用词(readLines方法),并保存在List中。之后再对获取的所有词进行筛选,去除停用词即可。本项目利用了list集合中的contains方法判断集合中是否已经存在字符串

service层对应的代码

public List<WordCloudData> getWordCloudData() {
    //获取停用词列表到List中
    FileReader fileReader = new FileReader("../../src/main/resources/static/info/停用词.txt");
    List<String> list = fileReader.readLines();
    //去除List集合中的无用词
    List<WordCloudData> words = wordCloudDataDao.getWordCloudData();
    List<WordCloudData> results = new ArrayList<>();
    int length = words.size();
    for(int i = 0;i < length;i++){
        if(!list.contains(words.get(i).getName())){
            results.add(words.get(i));
        }
    }
    return results;
}

关于hutool工具中封装的FileReader源码分析

hutool工具对java中一些繁琐的操作(比如日期转换,类型转换,文件读取等)进行了一些封装。由于本课程源码分析,因此我希望在阅读基本的项目代码的基础上,还能进一步了解java工具当中的部分源码。在上面的例子中,我使用了FileReader类,通过传入路径获取FileReader类对象,我们来看一下FileReader底层是怎么实现的

首先找到对应的构造方法,发现这个方法调用了另一个该类中的构造方法

public FileReader(String filePath) {
    this(filePath, DEFAULT_CHARSET);
}

这里的DEFAULT_CHARSET在源码中也有体现。首先FileReader继承FileWrapper,而在FileWrapper类中的static代码块中,声明了DEFAULT_CHARSET为UTF-8

static {
    DEFAULT_CHARSET = StandardCharsets.UTF_8;
}

发现调用该构造方法后,这个构造方法又调用了一个新的构造方法

public FileReader(String filePath, Charset charset) {
    this(FileUtil.file(filePath), charset);
}

下面这个构造方法被调用

public FileReader(File file, Charset charset) {
    super(file, charset);
    this.checkFile();
}

而FileUtil.file(filePath)方法在底层实际上调用了java中的File类,并且使用三元运算符判断用户传入的路径是否为空

public static File file(String path) {
    return null == path ? null : new File(getAbsolutePath(path));
}

checkFile方法用于判断文件是否存在,如果不存在则会抛出异常

private void checkFile() throws IORuntimeException {
    if (!this.file.exists()) {
        throw new IORuntimeException("File not exist: " + this.file);
    } else if (!this.file.isFile()) {
        throw new IORuntimeException("Not a file:" + this.file);
    }
}

通过以上分析,可以知道,FileReader对象实际上是一个java中File对象的增强版。

四、总结

本博客重点介绍了如何对word文档进行分词,并去除停用词的过程,顺便拓展了lombok注解和hutool文件工具类的底层源码。总的来说,通过这一部分的分析,我和队友进一步了解了项目的构建过程,为下一步的代码阅读打下了基础。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值