{"id":18600609,"url":"https://github.com/houbb/segment","last_synced_at":"2025-04-07T16:19:31.615Z","repository":{"id":44967807,"uuid":"233728741","full_name":"houbb/segment","owner":"houbb","description":"The jieba-analysis tool for java.（基于结巴分词词库实现的更加灵活优雅易用，高性能的 java 分词实现。支持词性标注。）","archived":false,"fork":false,"pushed_at":"2024-02-28T07:10:15.000Z","size":6103,"stargazers_count":148,"open_issues_count":2,"forks_count":28,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-31T14:12:41.505Z","etag":null,"topics":["benchmark","chinese","dfa","hmm","java","jieba","jieba-analysis","jieba-chinese","nlp","segment","segmentation","trie","trie-tree"],"latest_commit_sha":null,"homepage":"https://houbb.github.io/opensource/segment","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/houbb.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-01-14T01:19:25.000Z","updated_at":"2025-03-11T05:45:36.000Z","dependencies_parsed_at":"2023-01-21T23:16:35.145Z","dependency_job_id":"b03c63b8-cfb9-47a3-9dd9-2222cfa82a41","html_url":"https://github.com/houbb/segment","commit_stats":{"total_commits":86,"total_committers":4,"mean_commits":21.5,"dds":"0.15116279069767447","last_synced_commit":"7dd1eb26315c1fd7e86456826ef01e4d3ed72062"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/houbb%2Fsegment","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/houbb%2Fsegment/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/houbb%2Fsegment/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/houbb%2Fsegment/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/houbb","download_url":"https://codeload.github.com/houbb/segment/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247685634,"owners_count":20979085,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["benchmark","chinese","dfa","hmm","java","jieba","jieba-analysis","jieba-chinese","nlp","segment","segmentation","trie","trie-tree"],"created_at":"2024-11-07T02:04:43.700Z","updated_at":"2025-04-07T16:19:31.597Z","avatar_url":"https://github.com/houbb.png","language":"Java","readme":"# Segment\n\n[Segment](https://github.com/houbb/segment) 是基于结巴分词词库实现的更加灵活，高性能的 java 分词实现。\n\n愿景：成为 java 最好用的分词工具。\n\n[![Build Status](https://travis-ci.com/houbb/segment.svg?branch=master)](https://travis-ci.com/houbb/segment)\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.houbb/segment/badge.svg)](http://mvnrepository.com/artifact/com.github.houbb/segment)\n[![](https://img.shields.io/badge/license-Apache2-FF0080.svg)](https://github.com/houbb/segment/blob/master/LICENSE.txt)\n[![Open Source Love](https://badges.frapsoft.com/os/v2/open-source.svg?v=103)](https://github.com/houbb/segment)\n\n\u003e [在线体验](https://houbb.github.io/opensource/segment)\n\n## 创作目的\n\n分词是做 NLP 相关工作，非常基础的一项功能。\n\n[jieba-analysis](https://github.com/huaban/jieba-analysis) 作为一款非常受欢迎的分词实现，个人实现的 [opencc4j](https://github.com/houbb/opencc4j) 之前一直使用其作为分词。\n\n但是随着对分词的了解，发现结巴分词对于一些配置上不够灵活。\n\n（1）有很多功能无法指定关闭，比如 HMM 对于繁简体转换是无用的，因为繁体词是固定的，不需要预测。\n\n（2）最新版本的词性等功能好像也被移除了，但是这些都是个人非常需要的。\n\n（3）对于中文繁体分词支持不友好。\n\n所以自己重新实现了一遍，希望实现一套更加灵活，更多特性的分词框架。\n\n而且 jieba-analysis 的更新似乎停滞了，个人的实现方式差异较大，所以建立了全新的项目。\n\n## Features 特点\n\n- 面向用户的极简静态 api 设计\n\n- 面向开发者 fluent-api 设计，让配置更加优雅灵活\n\n- 详细的中文代码注释，便于源码阅读\n\n- 基于 DFA 实现的高性能分词\n\n- 基于 HMM 的新词预测\n\n- 支持不同的分词模式\n\n- 支持全角半角/英文大小写/中文繁简体格式处理\n\n- 允许用户自定义词库\n\n- 简单的词性标注实现\n\n- 支持字典等资源的主动释放\n\n### v-0.3.1 最新变更\n\n- 升级 heaven 依赖\n- 更新文档\n\n\u003e [变更日志](https://github.com/houbb/segment/blob/master/CHANGELOG.md)\n\n# 快速入门\n\n## 准备\n\njdk1.7+\n\nmaven 3.x+\n\n## maven 引入\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.github.houbb\u003c/groupId\u003e\n    \u003cartifactId\u003esegment\u003c/artifactId\u003e\n    \u003cversion\u003e0.3.1\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n相关代码参见 [SegmentHelperTest.java](https://github.com/houbb/segment/blob/master/src/test/java/com/github/houbb/segment/test/util/SegmentHelperTest.java)\n\n## 默认分词示例\n\n返回分词，下标等信息。\n\n```java\nfinal String string = \"这是一个伸手不见五指的黑夜。我叫孙悟空，我爱北京，我爱学习。\";\n\nList\u003cISegmentResult\u003e resultList = SegmentHelper.segment(string);\nAssert.assertEquals(\"[这是[0,2), 一个[2,4), 伸手不见五指[4,10), 的[10,11), 黑夜[11,13), 。[13,14), 我[14,15), 叫[15,16), 孙悟空[16,19), ，[19,20), 我爱[20,22), 北京[22,24), ，[24,25), 我爱[25,27), 学习[27,29), 。[29,30)]\", resultList.toString());\n```\n\n## 指定返回形式\n\n有时候我们根据自己的应用场景，需要选择不同的返回形式。\n\n`SegmentResultHandlers` 用来指定对于分词结果的处理实现，便于保证 api 的统一性。\n\n| 方法 | 实现 | 说明                         |\n|:---|:---|:---------------------------|\n| `common()` | SegmentResultHandler | 默认实现，返回 ISegmentResult 列表  |\n| `word()` | SegmentResultWordHandler | 只返回分词字符串列表                 |\n| `wordCount()` | SegmentResultWordHandler | key: 分词字符串; value: 分词出现的次数 |\n\n### 默认模式\n\n默认分词形式，等价于下面的写法\n\n```java\nList\u003cISegmentResult\u003e resultList = SegmentHelper.segment(string, SegmentResultHandlers.common());\n```\n\n### 只获取分词信息\n\n```java\nfinal String string = \"这是一个伸手不见五指的黑夜。我叫孙悟空，我爱北京，我爱学习。\";\n\nList\u003cString\u003e resultList = SegmentHelper.segment(string, SegmentResultHandlers.word());\nAssert.assertEquals(\"[这是, 一个, 伸手不见五指, 的, 黑夜, 。, 我, 叫, 孙悟空, ，, 我爱, 北京, ，, 我爱, 学习, 。]\", resultList.toString());\n```\n\n### 统计分词出现的次数\n\n我们通过 `SegmentResultHandlers.wordCount()` 指定统计出现次数的方法。\n\n```java\nfinal String string = \"这是一个伸手不见五指的黑夜。我叫孙悟空，我爱北京，我爱学习。\";\n\nMap\u003cString, Integer\u003e wordCount = SegmentHelper.segment(string, SegmentResultHandlers.wordCount());\nAssert.assertEquals(2, wordCount.get(\"我爱\").intValue());\nAssert.assertEquals(1, wordCount.get(\"黑夜\").intValue());\n```\n\n当然，这个在相似度等计算中出现频率较高。\n\n因此提供工具方法 `SegmentHelper.wordCount()`，上面的方法等价于：\n\n```java\nMap\u003cString, Integer\u003e wordCount = SegmentHelper.wordCount(string);\n```\n\n# 引导类\n\n## 说明\n\n针对灵活的配置，引入了 `SegmentBs` 作为引导类，解决工具类方法配置参数过多的问题。\n\n## 示例如下\n\n```java\nfinal String text = \"自定义一个很长的分词，开心！\";\n\nList\u003cISegmentResult\u003e resultList = SegmentBs.newInstance()\n        // 分词实现策略\n        .segment(Segments.defaults())\n        // 分词词组数据\n        .segmentData(SegmentPhraseDatas.mixed())\n        // 分词模式\n        .segmentMode(SegmentModes.dict())\n        // 格式化处理\n        .segmentFormat(SegmentFormats.defaults())\n        // 词性标注实现\n        .posTagging(SegmentPosTaggings.simple())\n        // 词性标注数据\n        .posData(SegmentPosDatas.mixed())\n        // 对文本进行分词处理\n        .segment(text, SegmentResultHandlers.common());\nAssert.assertEquals(\"[自定义一个很长的分词[0,10)/un, ，[10,11)/un, 开心[11,13)/a, ！[13,14)/un]\", resultList.toString());\n```\n\n所有的内置方法都是基于接口，可以自行定义实现。\n\n# 分词模式\n\n## 分词模式简介\n\n分词模式可以通过类 `SegmentModes` 工具类获取。\n\n| 序号 | 方法 | 准确度 | 性能 | 备注 |\n|:---|:---|:---|:---|:---|\n| 1 | search() | 高 | 一般 | 结巴分词的默认模式 |\n| 2 | dict() | 较高 | 一般 | 和 search 模式类似，但是缺少 HMM 新词预测 |\n| 3 | index() | 一般 | 高 | 尽可能多的返回词组信息，提高召回率 |\n| 4 | greedyLength() | 一般 | 高 | 贪心最大长度匹配，对准确度要求不高时可采用。 |\n\n## 使用方式\n\n针对灵活的配置，引入了 `SegmentBs` 作为引导类，解决工具类方法配置参数过多的问题。\n\n测试代码参见 [SegmentModeTest.java](https://github.com/houbb/segment/blob/master/src/test/java/com/github/houbb/segment/test/bs/SegmentBsModeTest.java)\n\n## search 模式\n\n`segmentMode()` 指定分词模式，不指定时默认就是 `SegmentModes.search()`。\n\n```java\nfinal String string = \"这是一个伸手不见五指的黑夜。\";\n\nList\u003cISegmentResult\u003e resultList = SegmentBs.newInstance()\n       .segmentMode(SegmentModes.search())\n       .segment(string);\n\nAssert.assertEquals(\"[这是[0,2), 一个[2,4), 伸手不见五指[4,10), 的[10,11), 黑夜[11,13), 。[13,14)]\", resultList.toString());\n```\n\n## dict 模式\n\n只依赖词库实现分词，没有 HMM 新词预测功能。\n\n```java\nfinal String string = \"这是一个伸手不见五指的黑夜。\";\n\nList\u003cISegmentResult\u003e resultList = SegmentBs.newInstance()\n        .segmentMode(SegmentModes.dict())\n        .segment(string);\nAssert.assertEquals(\"[这[0,1), 是[1,2), 一个[2,4), 伸手不见五指[4,10), 的[10,11), 黑夜[11,13), 。[13,14)]\", resultList.toString());\n```\n\n## index 模式\n\n这里主要的区别就是会返回 `伸手`、`伸手不见` 等其他词组。\n\n```java\nfinal String string = \"这是一个伸手不见五指的黑夜。\";\n\nList\u003cISegmentResult\u003e resultList = SegmentBs.newInstance()\n        .segmentMode(SegmentModes.index())\n        .segment(string);\nAssert.assertEquals(\"[这[0,1), 是[1,2), 一个[2,4), 伸手[4,6), 伸手不见[4,8), 伸手不见五指[4,10), 的[10,11), 黑夜[11,13), 。[13,14)]\", resultList.toString());\n```\n\n## GreedyLength 模式\n\n这里使用贪心算法实现，准确率一般，性能较好。\n\n```java\nfinal String string = \"这是一个伸手不见五指的黑夜。\";\n\nList\u003cISegmentResult\u003e resultList = SegmentBs.newInstance()\n        .segmentMode(SegmentModes.greedyLength())\n        .segment(string);\nAssert.assertEquals(\"[这[0,1), 是[1,2), 一个[2,4), 伸手不见五指[4,10), 的[10,11), 黑夜[11,13), 。[13,14)]\", resultList.toString());\n```\n\n# 格式化处理\n\n## 格式化接口\n\n可以通过 `SegmentFormats` 工具类获取对应的格式化实现，在分词时指定即可。\n\n| 序号 | 方法 | 名称 | 说明 |\n|:---|:---|:---|:---|\n| 1 | defaults() | 默认格式化 | 等价于小写+半角处理。 |\n| 2 | lowerCase() | 字符小写格式化 | 英文字符处理时统一转换为小写 |\n| 3 | halfWidth() | 字符半角格式化 | 英文字符处理时统一转换为半角 |\n| 4 | chineseSimple() | 中文简体格式化 |  用于支持繁体中文分词 |\n| 5 | none() | 无格式化 |  无任何格式化处理 |\n| 6 | chains(formats) | 格式化责任链 | 你可以针对上述的格式化自由组合，同时允许自定义格式化。 |\n\n## 默认格式化\n\n全角半角+英文大小写格式化处理，默认开启。\n\n这里的 `Ｑ` 为全角大写，默认会被转换处理。\n\n```java\nString text = \"阿Ｑ精神\";\nList\u003cISegmentResult\u003e segmentResults = SegmentHelper.segment(text);\n\nAssert.assertEquals(\"[阿Ｑ[0,2), 精神[2,4)]\", segmentResults.toString());\n```\n\n## 中文繁体分词\n\n无论是结巴分词还是当前框架，默认对繁体中文的分词都不友好。\n\n### 默认分词示例\n\n显然和简体中文的分词形式不同。\n\n```java\nString text = \"這是一個伸手不見五指的黑夜\";\n\nList\u003cString\u003e defaultWords = SegmentBs.newInstance()\n        .segment(text, SegmentResultHandlers.word());\nAssert.assertEquals(\"[這是, 一, 個, 伸手, 不見, 五指, 的, 黑夜]\", defaultWords.toString());\n```\n\n### 启用中文繁体分词\n\n指定分词中文格式化，可以得到符合我们预期的分词。\n\n```java\nString text = \"這是一個伸手不見五指的黑夜\";\n\nList\u003cString\u003e defaultWords = SegmentBs.newInstance()\n        .segmentFormat(SegmentFormats.chineseSimple())\n        .segment(text, SegmentResultHandlers.word());\nAssert.assertEquals(\"[這是, 一個, 伸手不見五指, 的, 黑夜]\", defaultWords.toString());\n```\n\n## 格式化责任链\n\n格式化的形式可以有很多，我们可以根据自己的需求自由组合。\n\n比如我们想同时启用默认格式化+中文简体格式化。\n\n```java\nfinal String text = \"阿Ｑ，這是一個伸手不見五指的黑夜\";\n\nList\u003cString\u003e defaultWords = SegmentBs.newInstance()\n        .segmentFormat(SegmentFormats.chains(SegmentFormats.defaults(),\n                SegmentFormats.chineseSimple()))\n        .segment(text, SegmentResultHandlers.word());\nAssert.assertEquals(\"[阿Ｑ, ，, 這是, 一個, 伸手不見五指, 的, 黑夜]\", defaultWords.toString());\n```\n\n# 自定义词库\n\n为了适应更多的应用场景，segment 支持自定义词典。\n\n## 定义方式\n\n`resources` 或者项目根目录新建文件 `segment_phrase_dict_define.txt`\n\n要求编码：UTF-8\n\n内容格式如下：\n\n```\n彩霞 78 n\n```\n\n第一个词是我们自定义的词，必填。\n\n第二个为这个词出现的词频，选填，默认为 3。\n\n第三个为词性，选填，默认为 un。（未知）\n\n三者用英文空格（` `）隔开。\n\n## 优先级\n\n用户自定义的词优先级更高，会覆盖系统原有的相同词。\n\n# 词性标注\n\n## 说明\n\n目前支持最简单版本的词性标注，暂定为 alpha 版本，后续引入基于 HMM 实现的词性标注。\n\n## 使用例子\n\n```java\nfinal String string = \"这是一个伸手不见五指的黑夜。\";\n\nList\u003cISegmentResult\u003e resultList = SegmentBs.newInstance()\n        .posTagging(SegmentPosTaggings.simple())\n        .segment(string);\n\nAssert.assertEquals(\"[这是[0,2)/un, 一个[2,4)/mq, 伸手不见五指[4,10)/i, 的[10,11)/ude1, 黑夜[11,13)/n, 。[13,14)/w]\", resultList.toString());\n```\n\n# 主动释放资源 \n\n## 说明\n\n分词是基于字典实现的，为了提升性能，字典初始化之后会缓存到内存中。 这对于 java web 服务端是没有太大问题的。\n\n有安卓客户端小伙伴反应，希望分词使用一次之后，可以主动释放资源。\n\n此功能为此而实现。\n\n## 使用\n\n方法在引导类中可以使用，如下：\n\n```java\n// 初始化引导类\nfinal SegmentBs segmentBs = SegmentBs.newInstance();\n\n// 主动释放资源\nsegmentBs.destroy();\n```\n\n### 例子\n\n实际例子：\n\n```java\n// 基本特性\nfinal SegmentBs segmentBs = SegmentBs.newInstance();\n\nfinal String string = \"这是一个伸手不见五指的黑夜。我叫孙悟空，我爱北京，我爱学习。\";\nList\u003cISegmentResult\u003e resultList = segmentBs.segment(string);\nAssert.assertEquals(\"[这是[0,2), 一个[2,4), 伸手不见五指[4,10), 的[10,11), 黑夜[11,13), 。[13,14), 我[14,15), 叫[15,16), 孙悟空[16,19), ，[19,20), 我爱[20,22), 北京[22,24), ，[24,25), 我爱[25,27), 学习[27,29), 。[29,30)]\", resultList.toString());\n\n// 资源释放\nsegmentBs.destroy();\n\n// 重新处理\nList\u003cISegmentResult\u003e resultList2 = segmentBs.segment(string);\nAssert.assertEquals(\"[这是[0,2), 一个[2,4), 伸手不见五指[4,10), 的[10,11), 黑夜[11,13), 。[13,14), 我[14,15), 叫[15,16), 孙悟空[16,19), ，[19,20), 我爱[20,22), 北京[22,24), ，[24,25), 我爱[25,27), 学习[27,29), 。[29,30)]\", resultList2.toString());\n```\n\n为了便于使用，**资源释放之后，如果再次分词，会重新初始化相关资源**。\n\n### 日志\n\n为了便于研发观察，自适应日志输出对应的字典加载和销毁信息。\n\n格式如下：\n\n```\n[DEBUG] [2023-03-23 11:16:53.010] [main] [c.g.h.s.s.t.i.SegmentTrieTree.getTrieTree] - [Segment]-[data-trie] init start\n[DEBUG] [2023-03-23 11:16:53.480] [main] [c.g.h.s.s.t.i.SegmentTrieTree.getTrieTree] - [Segment]-[data-trie] init end\n...\n\n[DEBUG] [2023-03-23 11:16:53.543] [main] [c.g.h.s.s.t.i.SegmentTrieTree.destroy] - [Segment]-[data-trie] destroy start\n[DEBUG] [2023-03-23 11:16:53.543] [main] [c.g.h.s.s.t.i.SegmentTrieTree.destroy] - [Segment]-[data-trie] destroy end\n...\n```\n\n# Benchmark 性能对比\n\n## 性能对比\n\n性能对比基于 jieba 1.0.2 版本，测试条件保持一致，保证二者都做好预热，然后统一处理。\n\n验证下来，默认模式性能略优于 jieba 分词，贪心模式是其性能 3 倍左右。\n\n备注：\n\n（1）默认模式和结巴 Search 模式一致。\n\n后期考虑 HMM 也可以配置是否开启，暂定为默认开启\n\n（2）后期将引入多线程提升性能。\n\n代码参见 [BenchmarkTest.java](https://github.com/houbb/segment/blob/master/src/test/java/com/github/houbb/segment/test/benchmark/BenchmarkTest.java)\n\n## 性能对比图\n\n相同长文本，循环 1W 次耗时。（Less is Better）\n\n![benchmark](https://github.com/houbb/segment/blob/master/benchmark.png)\n\n# 后期 Road-Map\n\n## 核心特性\n\n- HMM 词性标注\n\n- HMM 实体标注\n\n- CRF 算法实现\n\n- N 元组算法实现\n\n## 优化\n\n- 多线程的支持，性能优化\n\n- 双数组 DFA 实现，降低内存消耗\n\n# 创作感谢\n\n感谢 [jieba](https://github.com/fxsjy/jieba) 分词提供的词库，以及 [jieba-analysis](https://github.com/huaban/jieba-analysis) 的相关实现。\n\n# NLP 开源矩阵\n\n[pinyin 汉字转拼音](https://github.com/houbb/pinyin)\n\n[pinyin2hanzi 拼音转汉字](https://github.com/houbb/pinyin2hanzi)\n\n[segment 高性能中文分词](https://github.com/houbb/segment)\n\n[opencc4j 中文繁简体转换](https://github.com/houbb/opencc4j)\n\n[nlp-hanzi-similar 汉字相似度](https://github.com/houbb/nlp-hanzi-similar)\n\n[word-checker 拼写检测](https://github.com/houbb/word-checker)\n\n[sensitive-word 敏感词](https://github.com/houbb/sensitive-word)\n","funding_links":[],"categories":["人工智能"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhoubb%2Fsegment","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhoubb%2Fsegment","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhoubb%2Fsegment/lists"}