适配 ES 9.x 的中文 NER(命名实体识别)推理 API + 管道配置完整方案
本文档包含:中文 NER 外部模型服务(FastAPI)、ES 9.x 推理 API 配置、Ingest 管道、索引 Mapping、数据索引与搜索验证,全程适配 ES 9.x 特性,支持识别人名(PER)、机构名(ORG)、地名(LOC) 等核心实体。
一、前置准备
-
环境要求:
-
Python 3.10+、Elasticsearch 9.x(启用 ML 模块)、网络连通;
-
硬件:模型服务至少 4GB 内存(首次下载模型需额外 2-3GB 空间,轻量模型无需 GPU)。
-
-
安装 Python 依赖:
Bash
pip3 install fastapi uvicorn torch transformers
二、步骤1:部署中文 NER 外部模型服务
完整代码(优化注释,适配 ES 9.x 响应格式)
保存为 chinese_ner_service.py:
Python
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List, Union, Dict
from transformers import AutoTokenizer, AutoModelForTokenClassification, pipeline
from contextlib import asynccontextmanager
import torch
# 全局模型变量(启动时仅加载一次)
ner_pipeline = None
@asynccontextmanager
async def lifespan(app: FastAPI):
"""ES 9.x 推荐:服务启动时加载模型,关闭时释放资源"""
global ner_pipeline
print("正在加载中文 NER 模型(hfl/chinese-bert-wwm-ext)...")
# 加载开源中文 NER 模型,支持人名、机构名、地名识别
model_name = "hfl/chinese-bert-wwm-ext"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForTokenClassification.from_pretrained(model_name)
model.eval()
# 构建 NER 流水线,聚合相邻实体标签
ner_pipeline = pipeline(
"ner",
model=model,
tokenizer=tokenizer,
aggregation_strategy="simple" # 聚合相邻标签,避免实体拆分
)
# 启用 GPU 加速(如有)
if torch.cuda.is_available():
model.to("cuda")
print("GPU 加速已启用")
print("中文 NER 模型加载完成!")
yield
print("正在关闭服务...")
ner_pipeline = None
app = FastAPI(
title="中文 NER 神经分析器",
description="中文命名实体识别服务(适配 ES 9.x 推理 API)",
version="1.0.0",
lifespan=lifespan
)
class InferenceRequest(BaseModel):
"""ES 9.x 推理 API 标准请求格式"""
input: Union[str, List[str]]
def format_response(
tagged_text: str,
entities: List[Dict[str, str]]
) -> dict:
"""
格式化响应,适配 ES 9.x 解析规则
返回:带实体标记的文本 + 结构化实体列表
"""
return {
"choices": [
{
"message": {
"content": tagged_text, # 带标记的文本(如 [PER]张三[/PER]...)
"entities": entities # 结构化实体列表
}
}
]
}
def extract_entities(text: str) -> tuple[str, List[Dict[str, str]]]:
"""
核心 NER 逻辑:识别实体并标记
支持实体类型:PER(人名)、ORG(机构名)、LOC(地名)
"""
if not text or not text.strip():
return "", []
# 调用 NER 流水线
results = ner_pipeline(text)
# 解析结果:构建带标记的文本 + 实体列表
tagged_text = ""
entities = []
last_end = 0
for entity in results:
# 提取实体信息
start = entity["start"]
end = entity["end"]
entity_text = entity["word"]
entity_type = entity["entity_group"] # PER/ORG/LOC
# 拼接带标记的文本
tagged_text += text[last_end:start]
tagged_text += f"[{entity_type}]{entity_text}[/{entity_type}]"
last_end = end
# 收集结构化实体
entities.append({
"text": entity_text,
"type": entity_type,
"start": start,
"end": end
})
# 拼接剩余文本
tagged_text += text[last_end:]
return tagged_text, entities
@app.post("/analyze/chinese-ner")
async def analyze_chinese_ner(request: InferenceRequest):
"""中文 NER 接口,适配 ES 9.x 推理 API"""
global ner_pipeline
if ner_pipeline is None:
raise HTTPException(status_code=503, detail="中文 NER 模型未加载")
# 处理输入(支持单文本/多文本)
if isinstance(request.input, str):
texts = [request.input]
else:
texts = request.input
# 批量处理(取第一个文本,可扩展为批量返回)
tagged_text, entities = extract_entities(texts[0])
return format_response(tagged_text, entities)
@app.get("/health")
async def health():
"""ES 9.x 健康检查接口"""
return {
"status": "healthy",
"message": "中文 NER 模型已就绪",
"support_entities": ["PER(人名)", "ORG(机构名)", "LOC(地名)"]
}
启动服务
Bash
python3 -m uvicorn chinese_ner_service:app --port 8001
# 后台运行:nohup python3 -m uvicorn chinese_ner_service:app --port 8001 &
等待出现「中文 NER 模型加载完成!」,本地测试:
Bash
curl -X POST http://localhost:8001/analyze/chinese-ner \
-H "Content-Type: application/json" \
-d '{"input": "张三在阿里巴巴杭州总部参加会议"}'
三、步骤2:配置 ES 9.x 推理 API
前提:暴露本地服务(测试用 ngrok)
Bash
ngrok http 8001
# 复制 HTTPS 地址(如 https://def456.ngrok.io)
配置推理端点(测试环境,可直接复制)
JSON
PUT _inference/completion/chinese-ner-analyzer
{
"service": "custom",
"service_settings": {
"url": "https://def456.ngrok.io/analyze/chinese-ner", // 替换为你的 ngrok 地址
"headers": {
"Content-Type": "application/json"
},
"request": "{\"input\": ${input}}",
"response": {
"json_parser": {
"completion_result": "$.choices[*].message.content", // 提取带标记的文本
"entities": "$.choices[*].message.entities" // 提取结构化实体列表
}
}
}
}
验证配置
JSON
POST _inference/completion/chinese-ner-analyzer
{
"input": "张三在阿里巴巴杭州总部参加会议"
}
四、步骤3:创建 ES 9.x Ingest 管道
管道功能
-
调用 NER 推理 API;
-
提取带标记的文本到
content_ner; -
用 Script 处理器将实体拆分到
person、org、loc字段。
JSON
PUT _ingest/pipeline/chinese_ner_pipeline
{
"description": "中文 NER 分析管道(适配 ES 9.x)",
"processors": [
{
"inference": {
"model_id": "chinese-ner-analyzer",
"input_output": {
"input_field": "content",
"output_field": "content_ner"
},
"on_failure": [
{
"set": {
"field": "content_ner",
"value": "{{content}}"
}
}
]
}
},
{
"script": {
"description": "提取实体到单独字段",
"lang": "painless",
"source": """
// 初始化实体字段
ctx.person = new ArrayList();
ctx.org = new ArrayList();
ctx.loc = new ArrayList();
// 从推理结果中提取实体(若存在)
if (ctx.containsKey('inference') && ctx.inference.containsKey('entities')) {
for (def entity : ctx.inference.entities) {
def entityText = entity.text;
def entityType = entity.type;
if (entityType == 'PER') {
ctx.person.add(entityText);
} else if (entityType == 'ORG') {
ctx.org.add(entityText);
} else if (entityType == 'LOC') {
ctx.loc.add(entityText);
}
}
}
"""
}
}
]
}
五、步骤4:创建 ES 9.x 索引 Mapping
JSON
PUT /my-chinese-ner-index
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0
},
"mappings": {
"properties": {
"content": { // 原始文本
"type": "text",
"analyzer": "standard"
},
"content_ner": { // 带实体标记的文本(用 whitespace 分析器)
"type": "text",
"analyzer": "whitespace",
"fields": {
"keyword": {
"type": "keyword"
}
}
},
"person": { // 人名列表
"type": "keyword"
},
"org": { // 机构名列表
"type": "keyword"
},
"loc": { // 地名列表
"type": "keyword"
}
}
}
}
六、步骤5:索引数据与搜索验证
1. 索引测试数据
JSON
POST /my-chinese-ner-index/_doc?pipeline=chinese_ner_pipeline
{
"content": "张三在阿里巴巴杭州总部参加会议,李四去北京腾讯出差"
}
2. 验证索引结果
JSON
GET /my-chinese-ner-index/_doc/文档ID
预期返回:person: ["张三", "李四"]、org: ["阿里巴巴", "腾讯"]、loc: ["杭州", "北京"]。
3. 按实体搜索(可直接复制)
搜索"人名是张三"的文档
JSON
GET /my-chinese-ner-index/_search
{
"query": {
"term": {
"person": "张三"
}
},
"highlight": {
"fields": {
"content_ner": {}
}
}
}
搜索"机构名包含阿里巴巴"的文档
JSON
GET /my-chinese-ner-index/_search
{
"query": {
"terms": {
"org": ["阿里巴巴", "腾讯"]
}
}
}
七、生产环境优化配置
1. 推理 API 安全配置
JSON
PUT _inference/completion/chinese-ner-analyzer
{
"service": "custom",
"service_settings": {
"url": "https://你的API网关地址/prod/analyze/chinese-ner",
"headers": {
"x-api-key": "${api_key}",
"Content-Type": "application/json"
},
"secret_parameters": {
"api_key": "你的API密钥"
},
"request": "{\"input\": ${input}}",
"response": {
"json_parser": {
"completion_result": "$.choices[*].message.content",
"entities": "$.choices[*].message.entities"
}
}
}
}
2. 设置管道为索引默认
JSON
PUT /my-chinese-ner-index/_settings
{
"index.default_pipeline": "chinese_ner_pipeline"
}
八、故障排查
-
模型下载失败 :手动下载模型到
~/.cache/huggingface/transformers; -
ES 推理 API 调用失败:检查 ngrok 地址是否正确、服务是否启动;
-
实体未提取 :检查 Script 处理器语法、推理结果是否包含
entities字段。