Appearance
倒排索引与分词
倒排索引
正排 vs 倒排
正排索引:
┌─────┬──────────────┐
│ ID │ Document │
├─────┼──────────────┤
│ 1 │ 我爱中国 │
│ 2 │ 中国有多长 │
│ 3 │ 中国加油 │
└─────┴──────────────┘
倒排索引:
┌─────┬────────────┐
│Term │ Postings │
├─────┼────────────┤
│ 我 │ [1] │
│ 爱 │ [1] │
│ 中国│ [1,2,3] │
│ 有 │ [2] │
│ 多长│ [2] │
│ 加油│ [3] │
└─────┴────────────┘ES中的倒排索引结构
java
// Lucene TermIndex
{
"term": "中国",
"docFreq": 3, // 出现在多少文档
"totalTermFreq": 4, // 出现总次数
"postingList": [
{docId: 1, positions: [1]}, // 位置信息
{docId: 2, positions: [0]},
{docId: 3, positions: [0]}
]
}组成结构
| 组成部分 | 说明 |
|---|---|
| Term Dictionary | terms按字典序排序 |
| Term Index | terms的FST索引,加速定位 |
| Posting List | 每个term对应的文档列表 |
| Position | term在文档中的位置 |
| Frequency | term在文档中出现次数 |
分词器
分词流程
原始文本 → Character Filter → Tokenizer → Token Filter → Tokens
↓
多个过滤器链式处理内置分词器
| 分词器 | 说明 | 示例 |
|---|---|---|
| standard | 默认,Unicode分词 | "I love China" → [i, love, china] |
| whitespace | 空格分词 | "I love China" → [i, love, china] |
| simple | 字母分词,非字母分割 | "I love-China" → [i, love, china] |
| keyword | 不分词,返回原文本 | "I love China" → [i love china] |
| pattern | 正则分词 | 按正则表达式 |
| stop | 移除停用词 | 移除the、a等 |
中文分词器
| 分词器 | 说明 |
|---|---|
| IK | 业界最常用,支持ik_smart/ik_max_word |
| jieba | Python结巴的Java版本 |
| hanlp | 哈工大出品,学术背景强 |
| ansj | 清华nlg实验室 |
json
// IK配置
{
"settings": {
"analysis": {
"analyzer": {
"ik_analyzer": {
"type": "custom",
"tokenizer": "ik_max_word"
}
}
}
}
}自定义分词器
json
PUT /my_index
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"type": "custom",
"char_filter": ["html_strip"],
"tokenizer": "standard",
"filter": ["lowercase", "stop", "porter_stem"]
}
}
}
}
}面试考点
Q: 为什么倒排索引搜索快?
- term直接定位,无需全表扫描
- 只扫包含查询词的文档
- FST索引加速term定位
Q: 分词器选择考虑什么?
- 语言:中文/英文
- 场景:搜索/索引
- 性能:精确度vs速度
Q: 停用词怎么配置?
json
{
"settings": {
"analysis": {
"filter": {
"my_stop": {
"type": "stop",
"stopwords": ["the", "a", "an"]
}
}
}
}
}