当前位置:   article > 正文

spring boot对接hanlp的对接示例(推荐的一种实践方式)_springboot hanlp

springboot hanlp

一、背景

我们的系统应用,总离不开留言和评论功能,甚至是Im即时通讯,也就产生了审核的需求。如果全部依赖人工来做,显然不现实。在当今chatgpt火爆的时候,如果我们连静态的分词都还做不到,实是惭愧万分。

我们不要求做到ai机器人那么强大,还需要去理解用户的上下文,只需要根据输入的一段文本,进行语义上的拆分(即分词)。经过选型,我们选择了一款免费版的hanlp工具,当然你也可以选择市面上的其他工具,如网易易盾、微盾、Jieba等等。(这里就不说一些大厂的在线服务了)

我们有一个硬核需求,就是要自定义单词,相对方便灵活。因为敏感词的变化太快了~~

二、源码实现

引入jar

这里不建议你使用portable-1.8.4,区别是portable-1.8.4包含了data目录。而我们一般是将data目录放置在jar包的外部,这也是我不推荐你引用portable-1.8.4包的原因,使用轻量级的1.8.4就够了。

 <dependency>
            <groupId>com.hankcs</groupId>
            <artifactId>hanlp</artifactId>
            <version>1.8.4</version>
<!--            <version>portable-1.8.4</version>-->
        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

下面我截图以对比二者,但是你如果直接使用1.8.4,会发现远程仓库没有该包,需要你手动下载然后上传至你自己的私有仓库中。
在这里插入图片描述
在这里插入图片描述
先手工下载jar和配置文件:hanlp-release.zip

下载至本地,把jar和source包先后upload至nexus等私有仓库中。

该包还有一个hanlp.properties文件,你需要修改配置root=你自己的HanLP数据包的目录
在这里插入图片描述

hanlp.properties

只需要修改这一项,其他的保持不变。

root=/Users/xxx/Desktop/data-for-1.7.5/
  • 1

在这里插入图片描述在这里插入图片描述

1、配置

# hanlp自定义单词
hanlp:
  define:
    wordlist: 傻逼,杂种细胞
  • 1
  • 2
  • 3
  • 4

2、接口设计

在这里插入图片描述

import cn.hutool.core.date.DateUtil;
import com.xxx.ws.test.hanlp.HanlpService;
import io.swagger.annotations.Api;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

/**
 * hanlp的测试入口类.
 */
@Api(tags = "hanlp")
@RestController
@RequiredArgsConstructor
public class HanlpApiController {
    private final HanlpService hanlpService;

    @PatchMapping("/hanlp/add/{word}")
    public ResponseEntity<?> add(@PathVariable String word) {
        hanlpService.add(word);
        return ResponseEntity.ok(DateUtil.now());
    }

    @DeleteMapping("/hanlp/remove/{word}")
    public ResponseEntity<?> remove(@PathVariable String word) {
        hanlpService.remove(word);
        return ResponseEntity.ok(DateUtil.now());
    }

    @PostMapping("/hanlp/split")
    public ResponseEntity<?> split(@RequestBody String content) {
        return ResponseEntity.ok(hanlpService.segmentWord(content));
    }
}
  • 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

3、实现类

import com.google.common.collect.Lists;
import com.hankcs.hanlp.HanLP;
import com.hankcs.hanlp.dictionary.CustomDictionary;
import com.hankcs.hanlp.seg.common.Term;
import com.hankcs.hanlp.utility.Predefine;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class HanlpService {
    // 多个单词之间使用逗号隔开
    @Value("#{'${hanlp.define.wordlist:}'.split(',')}")
    private List<String> myDefineWordList;

    @PostConstruct
    public void init() {
        // 从环境变量里读取
        Predefine.HANLP_PROPERTIES_PATH = System.getProperty("hanlp_properties_path");

        // 将自定义的单词加入到自定义词典
        myDefineWordList.stream().forEach(word -> {
            this.add(word);
        });
    }

    public List<String> segmentWord(String content) {
        if (StringUtils.isEmpty(content)) {
            return Lists.newArrayList();
        }

        List<Term> termList = HanLP.segment(content);

        List<String> words = termList.stream().map(term -> term.word).collect(Collectors.toList());

        return words;
    }

    public void add(String word) {
        CustomDictionary.add(word);
    }

    public void remove(String word) {
        CustomDictionary.remove(word);
    }

}

  • 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
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

三、测试验证

1、初始化时,已配置自定义的单词

  • 先验证分词

curl -X POST -H “Accept:/” -H “Content-Type:application/json” -d “你是个傻逼还是杂种细胞呢” “http://localhost:8085/hanlp/split”
返回结果是:[
“你”,
“是”,
“个”,
“傻逼”,
“还是”,
“杂种细胞”,
“呢”
]

证明自定义的单词生效了。

  • 再删掉自定义单词

curl -X DELETE -H “Accept:/” -H “Content-Type:application/x-www-form-urlencoded” “http://localhost:8085/hanlp/remove/”

  • 再去切割上一句话,则是如下结果
    在这里插入图片描述

  • 再新增自定义单词

curl -X PATCH -H “Accept:/” -H “Content-Type:application/x-www-form-urlencoded” “http://localhost:8085/hanlp/add/”

  • 第三次去验证分词,又和最初一样,证明新增的自定义单词生效。

2、初始化时,未配置自定义的单词

这里就不赘述,第一次切割单词"杂种细胞"为两个单词"杂种"和"细胞",第二步新增单词"杂种细胞"后,就不会拆分成两个单词,第三步删除自定义单词"杂种细胞",效果又回到第一次。

四、总结

  • Predefine.HANLP_PROPERTIES_PATH,你需要在程序启动的过程中,对它进行赋值,为hanlp.properties文件所在的目录。比如 Predefine.HANLP_PROPERTIES_PATH = “/Users//Desktop/data-for-1.7.5/hanlp.properties”;

  • 本文花费比较多的地方截图和补充说明在准备工作,环境配置相对可能是一个坑。因为我们的需求是需要自定义单词。(如果你不需要自定义单词,你可以直接使用portable-1.8.4,压根都没有这么多步骤)

  • 话说回来,如果你对接的是分词需求,而且是离线版的hanlp,自定义的需求就是我们的硬核需求,不可或缺。(否则你直接使用rest版本的即可)

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号