Appearance
文本处理与 Embedding 技术
3.1 文本清洗、分段、分块策略
3.1.1 文本清洗
清洗步骤
去除噪声:
- 去除HTML标签
- 去除特殊字符
- 去除多余空格
- 统一大小写
标准化处理:
- 拼写纠错
- 同义词替换
- 数字格式化
- 日期标准化
停用词处理:
- 去除常见停用词(如"的"、"了"、"是"等)
- 自定义停用词列表
实现代码
python
import re
import string
from nltk.corpus import stopwords
# 文本清洗函数
def clean_text(text):
# 去除HTML标签
text = re.sub(r'<[^>]+>', '', text)
# 去除特殊字符
text = text.translate(str.maketrans('', '', string.punctuation))
# 去除多余空格
text = re.sub(r'\s+', ' ', text).strip()
# 转小写
text = text.lower()
# 去除停用词
stop_words = set(stopwords.words('chinese'))
words = text.split()
filtered_words = [word for word in words if word not in stop_words]
return ' '.join(filtered_words)
# 示例
raw_text = "这是一个 <b>示例</b> 文本!包含了一些多余的 空格和特殊字符。"
cleaned_text = clean_text(raw_text)
print(cleaned_text)3.1.2 文本分段
分段策略
- 按段落:根据换行符分段
- 按章节:根据标题、小标题分段
- 按逻辑:根据语义内容分段
实现代码
python
# 文本分段函数
def split_into_paragraphs(text):
# 按换行符分段
paragraphs = text.split('\n')
# 过滤空段落
paragraphs = [p.strip() for p in paragraphs if p.strip()]
return paragraphs
# 示例
text = "这是第一段。\n\n这是第二段。\n\n这是第三段。"
paragraphs = split_into_paragraphs(text)
print(paragraphs)3.1.3 文本分块(Chunk)策略
分块方法
固定长度分块:
- 按字符数分块
- 按词数分块
- 按句子数分块
语义分块:
- 基于句子边界
- 基于段落边界
- 基于语义相似度
重叠分块:
- 相邻块之间保留一定重叠内容
- 提高上下文连贯性
分块策略对比
| 分块策略 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 固定长度 | 简单易实现 | 可能破坏语义完整性 | 结构化文本 |
| 语义分块 | 保持语义完整性 | 实现复杂 | 非结构化文本 |
| 重叠分块 | 提高上下文连贯性 | 增加存储和计算成本 | 长文档处理 |
实现代码
python
# 固定长度分块函数
def chunk_text(text, chunk_size=1000, overlap=100):
chunks = []
start = 0
text_length = len(text)
while start < text_length:
end = min(start + chunk_size, text_length)
chunks.append(text[start:end])
start += chunk_size - overlap
return chunks
# 基于句子的分块函数
def chunk_by_sentences(text, max_chunk_size=1000):
import nltk
nltk.download('punkt')
from nltk.tokenize import sent_tokenize
sentences = sent_tokenize(text)
chunks = []
current_chunk = ""
for sentence in sentences:
if len(current_chunk) + len(sentence) <= max_chunk_size:
current_chunk += sentence + " "
else:
chunks.append(current_chunk.strip())
current_chunk = sentence + " "
if current_chunk:
chunks.append(current_chunk.strip())
return chunks
# 示例
long_text = "这是一个很长的文本..." # 实际使用时替换为真实文本
chunks = chunk_text(long_text, chunk_size=500, overlap=50)
print(f"生成了 {len(chunks)} 个分块")
print(chunks[0])3.2 分词、Embedding(词向量)原理
3.2.1 分词技术
中文分词
- 基于规则的分词:正向最大匹配、逆向最大匹配
- 基于统计的分词:隐马尔可夫模型、条件随机场
- 基于深度学习的分词:BERT、LSTM-CRF
分词工具
- jieba:Python 中最常用的中文分词库
- HanLP:支持多种NLP任务的工具包
- THULAC:清华大学开发的分词工具
- PKUSeg:北京大学开发的分词工具
实现代码
python
import jieba
# 分词示例
text = "企业私有知识库落地实战"
tokens = list(jieba.cut(text))
print(tokens) # ['企业', '私有', '知识库', '落地', '实战']
# 自定义词典
jieba.add_word("知识库")
tokens = list(jieba.cut(text))
print(tokens) # ['企业', '私有', '知识库', '落地', '实战']3.2.2 Embedding 原理
什么是 Embedding?
Embedding 是将离散的符号(如单词、句子、文档)映射到连续的向量空间的过程,使得语义相似的符号在向量空间中距离更近。
Embedding 的作用
- 语义表示:捕捉词语的语义信息
- 降维:将高维离散空间映射到低维连续空间
- 特征提取:为下游任务提供有意义的特征
- 泛化能力:帮助模型处理未见过的词汇
Embedding 方法
静态 Embedding:
- Word2Vec
- GloVe
- FastText
动态 Embedding:
- BERT
- RoBERTa
- DistilBERT
句子/文档 Embedding:
- Sentence-BERT
- Doc2Vec
- Universal Sentence Encoder
3.3 开源 Embedding 模型选型与使用
3.3.1 常用开源 Embedding 模型
| 模型 | 组织 | 语言 | 维度 | 特点 |
|---|---|---|---|---|
| BGE | BAAI | 多语言 | 768/1024 | 性能优异,支持多语言 |
| M3E | 智谱AI | 中文 | 768 | 专为中文优化 |
| text2vec | shibing624 | 中文 | 768 | 轻量高效 |
| Sentence-BERT | UKP Lab | 多语言 | 768 | 通用性强 |
| E5 | Microsoft | 多语言 | 768/1024 | 检索任务表现好 |
3.3.2 BGE 模型使用
安装依赖
bash
pip install sentence-transformers使用示例
python
from sentence_transformers import SentenceTransformer
# 加载 BGE 模型
model = SentenceTransformer('BAAI/bge-base-zh-v1.5')
# 生成文本嵌入
texts = ["企业私有知识库", "RAG 技术原理", "向量数据库"]
embeddings = model.encode(texts)
print(f"嵌入维度: {embeddings.shape}")
print(f"第一个文本的嵌入向量: {embeddings[0][:5]}")
# 计算相似度
from sklearn.metrics.pairwise import cosine_similarity
similarity = cosine_similarity([embeddings[0]], [embeddings[1]])[0][0]
print(f"相似度: {similarity}")3.3.3 M3E 模型使用
安装依赖
bash
pip install sentence-transformers使用示例
python
from sentence_transformers import SentenceTransformer
# 加载 M3E 模型
model = SentenceTransformer('moka-ai/m3e-base')
# 生成文本嵌入
texts = ["企业私有知识库", "RAG 技术原理", "向量数据库"]
embeddings = model.encode(texts)
print(f"嵌入维度: {embeddings.shape}")
print(f"第一个文本的嵌入向量: {embeddings[0][:5]}")3.3.4 text2vec 模型使用
安装依赖
bash
pip install text2vec使用示例
python
from text2vec import SentenceModel
# 加载 text2vec 模型
model = SentenceModel()
# 生成文本嵌入
texts = ["企业私有知识库", "RAG 技术原理", "向量数据库"]
embeddings = model.encode(texts)
print(f"嵌入维度: {embeddings.shape}")
print(f"第一个文本的嵌入向量: {embeddings[0][:5]}")3.4 向量数据库核心原理
3.4.1 向量数据库的作用
- 高效存储:专门优化向量数据的存储结构
- 快速检索:支持相似度搜索和近似最近邻搜索
- 可扩展性:处理大规模向量数据
- 多样化查询:支持多种相似度度量和查询方式
3.4.2 向量存储原理
存储结构
- 向量索引:加速相似性搜索
- 元数据存储:存储与向量相关的附加信息
- 压缩技术:减少存储空间
相似度度量
- 余弦相似度:衡量两个向量方向的相似性
- 欧氏距离:衡量两个向量空间距离
- 曼哈顿距离:衡量两个向量的城市街区距离
- 汉明距离:衡量二进制向量的差异
3.4.3 向量索引技术
索引类型
树结构索引:
- KD-Tree
- Ball Tree
哈希索引:
- Locality Sensitive Hashing (LSH)
图索引:
- HNSW (Hierarchical Navigable Small World)
- IVF (Inverted File)
量化索引:
- Product Quantization (PQ)
- Scalar Quantization (SQ)
索引选择策略
| 索引类型 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| HNSW | 高查询速度,高准确性 | 内存消耗大 | 内存充足的场景 |
| IVF | 平衡速度和准确性 | 调参复杂 | 一般场景 |
| LSH | 构建速度快 | 准确性较低 | 大规模数据 |
| PQ | 存储效率高 | 查询速度较慢 | 存储空间受限 |
3.4.4 向量数据库操作
基本操作
- 插入:添加新的向量和元数据
- 查询:基于相似度搜索向量
- 更新:修改现有向量或元数据
- 删除:移除向量和元数据
高级操作
- 批量操作:批量插入、更新、删除
- 过滤查询:结合元数据进行过滤
- 范围查询:查找指定相似度范围内的向量
- 聚合查询:对查询结果进行聚合分析
3.5 本章小结
- 学习了文本清洗、分段、分块的策略和实现
- 掌握了分词技术和 Embedding 原理
- 了解了常用开源 Embedding 模型的选型与使用
- 熟悉了向量数据库的核心原理和索引技术
这些知识为我们后续构建 RAG 系统的文本处理 pipeline 打下了基础。在接下来的章节中,我们将深入学习向量数据库的实战应用,为知识库系统的检索功能做好准备。
