架构设计
┌─────────────────────────────────────────────────┐│ Znlp(静态门面) │ 应用代码主要接触这一层├─────────────────────────────────────────────────┤│ ZnlpSystem(record,持有 ServiceRegistry) │ 进程级单例├─────────────────────────────────────────────────┤│ ServiceRegistry(基于接口的轻量 DI) │ 支持父子容器├─────────────────────────────────────────────────┤│ ModuleLoader + SystemModule 实现 │ 扫描 znlp-modules.idx├─────────────────────────────────────────────────┤│ 能力模块:Segment / Pinyin / Highlight / Trans ││ 独立组件:Duckling(静态单例)/ FastText │├─────────────────────────────────────────────────┤│ NlpResourceLoader + 三个 ResourceFactory │ 本地文件 > 本地 Jar > Classpath└─────────────────────────────────────────────────┘主库共 399 个 Java 源文件,包根 dev.znlp。另有 dev.znlp.starspace 包(StarSpace 移植),不在核心能力范围内。
ModuleLoader 扫描 classpath 中所有 META-INF/znlp-modules.idx(因此第三方 jar 也能贡献模块),按 SystemModule.getPriority() 升序加载(数值越小越早),并根据配置的 disabledModules 跳过指定模块。
主库 znlp/src/main/resources/META-INF/znlp-modules.idx:
| 模块 | 优先级 | 职责 |
|---|---|---|
CoreModule(名 core) |
10 | 注册 NlpResourceLoader,是所有其他模块的前置 |
SegmentModule |
— | 分词、词性、NER、人名相关的 10 个服务 |
PinyinModule |
— | PinyinDict、PinyinSplitPerceptron、PinyinService |
HighlightModule |
— | SmartHighlighter(构造时注入 PinyinService) |
TransModule |
— | TransformService |
CoreModule 优先级为 10 且最先加载是必要的:其余模块都要通过 NlpResourceLoader 取资源。
ServiceRegistry
Section titled “ServiceRegistry”service.base.dev.znlp.ServiceRegistry 实现 ServiceLocator,是一个基于接口的轻量 DI 容器,不是 Spring 那种通用框架。
特点:
- 按接口注册、按接口查找:
getService(Class)支持继承和接口的智能查找 - 三种生命周期:
registerFactory(工厂,可选单例)、registerSingleton(实例单例)、registerClass/registerSingletonClass/registerPrototypeClass(按类注册) - 父子容器:
new ServiceRegistry(ServiceLocator parent),子容器查不到时向上委托 - 找不到抛
ServiceNotFoundException,不返回 null
SegmentModule 注册的 10 个服务:CoreDictionarySplitAlgorithm、CoreDictionary(factory 单例)、BiGramTableDictionary、PersonNamePerceptron、CwsPerceptron、PosPerceptron、NERPerceptron、CwsSplitAlgorithm、ResourceUserDictionary、AtomSplitAlgorithm。
NlpResourceLoader 为每个存在的 dataDir 依次挂两个 factory,最后加 classpath factory,形成三级回落:
FileNlpResourceFactory(dataDir[i]) 目录下的散文件JarNlpResourceFactory(dataDir[i]) 目录下 jar 内的文件...(对每个 dataDir 重复)ClasspathNlpResourceFactory znlp-resources jar即 本地文件 > 本地 Jar > Classpath。资源按 path:charset 缓存,同一资源不重复读取。
派生缓存(如二元语法表约 40 MB)写入 cache-dir,通过资源旁的 .hash 文件做失效判断。
auto-download-resource=true 时,资源缺失会尝试从华为云 Maven 镜像下载——但当前因路径前缀不匹配而实际不会触发,详见配置项参考。
SegmentRecipe.build() 产出 PipelineSegmenter,按固定阶段执行。理解阶段顺序是理解各种 with* 语义的前提:
1. 字符归一化(addNormalizer)2. 原子识别(AtomSplitAlgorithm)—— 数字、字母、标点等不可再分的片段3. 候选铺设: - 核心词典(CoreDictionary) - 规则(withRules,抬升词频) - 额外候选源(addCandidate)4. 选路: - 词典配方 → 二元语法 Viterbi(PathKind.VITERBI) - 感知机配方 → CWS 感知机线性解码(PathKind.LINEAR),不跑二元语法5. 约束过滤(addConstraint)6. 选路后处理(顺序很重要): a. 纠错词典(withCorrections)—— 优先级高于用户词典 b. 用户词典(withUserDictionary)—— 合并相邻词,两端须落在已有词边界7. 标注: - 人名(PersonNamePerceptron) - 词性(PosPerceptron) - NER(NerProcessor,合并 B/M/E 跨度后写回 Nature) - 自定义标注器(addAnnotator)8. 索引子词(indexTerms)三种「词进入结果」的路径语义(来自 SegmentRecipe 类 Javadoc):
| 机制 | 时机 | 是否参与 Viterbi |
|---|---|---|
核心词典 / addCandidate |
选路前铺候选 | 是 |
withRules |
选路前铺候选并抬词频 | 是(仅词典配方有效) |
withUserDictionary |
选路后合并 | 否 |
withCorrections |
选路后,优先级高于用户词典 | 否 |
用户词典不进词图这一点解释了两个常见现象:它能把 ["长江","大桥"] 粘成 ["长江大桥"],但无法切开一个已被核心词典认定的词;而且它的权重是固定的 WEIGHT = 1000,不参与概率竞争。
五个能力共用 dev.znlp.perceptron:
PerceptronInstance(抽象点:标签集、特征提取、语料解析、评估) ↓ CharBasedPerceptronInstance(字符级任务基类)PerceptronTrainer.train(...) ↓PerceptronTrainModel ──compress()──→ saveModelToDir() / saveModelBinFile() ↓ toModel()PerceptronModel ──getDecoder()──→ Viterbi / OptimizedViterbi / Quick Decoder复用这套框架训练新任务,只需实现 PerceptronInstance(getLables、getFeatureFun、getAnnotateTextParser、getEvaluateFunction、tansform),其余交给 PerceptronTrainer。PosPerceptron.train 是最清晰的完整范例。
特征模板在 perceptron/feature/ 下(CharDSLFeatureExtractor、FeatureTemplate 等),用 DSL 描述字符级特征窗口。
仓库 docs/设计架构/ 下有更深入的原始设计文档:
| 文档 | 内容 |
|---|---|
分词.md |
分词配方与阶段划分的设计 |
Duckling.md |
规则图解析 + 消歧的设计 |
FastText.md |
fastText 移植的设计与格式兼容 |
基准.md |
JMH 基准的方法论与命令 |
测试.md |
测试策略与 tag 约定 |
README.md |
设计文档索引 |
模块内另有若干 README,与代码抽查一致,可作为补充:highlight/README.md、newwords/README.md、newwords/scorer/README*.md、fasttext/README.md、base/resources/README.md、starspace/README_*.md。