Skip to content

文本处理与 Embedding 技术

3.1 文本清洗、分段、分块策略

3.1.1 文本清洗

清洗步骤

  1. 去除噪声

    • 去除HTML标签
    • 去除特殊字符
    • 去除多余空格
    • 统一大小写
  2. 标准化处理

    • 拼写纠错
    • 同义词替换
    • 数字格式化
    • 日期标准化
  3. 停用词处理

    • 去除常见停用词(如"的"、"了"、"是"等)
    • 自定义停用词列表

实现代码

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)策略

分块方法

  1. 固定长度分块

    • 按字符数分块
    • 按词数分块
    • 按句子数分块
  2. 语义分块

    • 基于句子边界
    • 基于段落边界
    • 基于语义相似度
  3. 重叠分块

    • 相邻块之间保留一定重叠内容
    • 提高上下文连贯性

分块策略对比

分块策略优点缺点适用场景
固定长度简单易实现可能破坏语义完整性结构化文本
语义分块保持语义完整性实现复杂非结构化文本
重叠分块提高上下文连贯性增加存储和计算成本长文档处理

实现代码

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 方法

  1. 静态 Embedding

    • Word2Vec
    • GloVe
    • FastText
  2. 动态 Embedding

    • BERT
    • RoBERTa
    • DistilBERT
  3. 句子/文档 Embedding

    • Sentence-BERT
    • Doc2Vec
    • Universal Sentence Encoder

3.3 开源 Embedding 模型选型与使用

3.3.1 常用开源 Embedding 模型

模型组织语言维度特点
BGEBAAI多语言768/1024性能优异,支持多语言
M3E智谱AI中文768专为中文优化
text2vecshibing624中文768轻量高效
Sentence-BERTUKP Lab多语言768通用性强
E5Microsoft多语言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 向量索引技术

索引类型

  1. 树结构索引

    • KD-Tree
    • Ball Tree
  2. 哈希索引

    • Locality Sensitive Hashing (LSH)
  3. 图索引

    • HNSW (Hierarchical Navigable Small World)
    • IVF (Inverted File)
  4. 量化索引

    • Product Quantization (PQ)
    • Scalar Quantization (SQ)

索引选择策略

索引类型优点缺点适用场景
HNSW高查询速度,高准确性内存消耗大内存充足的场景
IVF平衡速度和准确性调参复杂一般场景
LSH构建速度快准确性较低大规模数据
PQ存储效率高查询速度较慢存储空间受限

3.4.4 向量数据库操作

基本操作

  • 插入:添加新的向量和元数据
  • 查询:基于相似度搜索向量
  • 更新:修改现有向量或元数据
  • 删除:移除向量和元数据

高级操作

  • 批量操作:批量插入、更新、删除
  • 过滤查询:结合元数据进行过滤
  • 范围查询:查找指定相似度范围内的向量
  • 聚合查询:对查询结果进行聚合分析

3.5 本章小结

  • 学习了文本清洗、分段、分块的策略和实现
  • 掌握了分词技术和 Embedding 原理
  • 了解了常用开源 Embedding 模型的选型与使用
  • 熟悉了向量数据库的核心原理和索引技术

这些知识为我们后续构建 RAG 系统的文本处理 pipeline 打下了基础。在接下来的章节中,我们将深入学习向量数据库的实战应用,为知识库系统的检索功能做好准备。