查詢的倒排索引
1. 什麼是倒排索引?
倒排索引(Inverted Index)是一種數據結構,用於快速查找包含特定詞彙的文檔。它是搜索引擎的核心技術之一。
1.1 基本概念
- 正排索引 :文檔 ID → 文檔內容(詞列表)
- 倒排索引 :詞 → 包含該詞的文檔 ID 列表
1.2 爲什麼叫 ” 倒排 ”?
倒排索引將傳統的 ” 文檔包含哪些詞 ” 的關係倒轉爲 ” 詞出現在哪些文檔中 ”,因此稱爲 ” 倒排 ”。
2. 倒排索引的結構
2.1 基本結構
詞項 → 文檔頻率 → 文檔列表
2.2 詳細結構
詞項 → {
文檔頻率: N,
文檔列表: [{ 文檔 ID: 1, 詞頻: 2, 位置: [0, 5]},
{文檔 ID: 3, 詞頻: 1, 位置: [2]}
]
}
3. 倒排索引的工作原理
3.1 構建過程
- 文檔預處理 :分詞、去停用詞、詞幹提取
- 詞項統計 :統計每個詞在文檔中的出現頻率和位置
- 索引構建 :建立詞項到文檔的映射關係
3.2 查詢過程
- 查詢解析 :將查詢字符串分詞
- 索引查找 :在倒排索引中查找每個詞項
- 結果合併 :合併多個詞項的文檔列表
- 排序返回 :按相關性排序返回結果
4. Go 語言實現倒排索引
4.1 數據結構定義
package main
import (
"fmt"
"sort"
"strings"
)
// 文檔信息
type Document struct {
ID int
Text string
}
// 詞項在文檔中的位置信息
type Posting struct {
DocID int
Frequency int
Positions []int}
// 倒排索引項
type InvertedIndexItem struct {
Term string
DocFreq int
Postings []Posting}
// 倒排索引
type InvertedIndex struct {Index map[string]*InvertedIndexItem
}
// 創建新的倒排索引
func NewInvertedIndex() *InvertedIndex {
return &InvertedIndex{Index: make(map[string]*InvertedIndexItem),
}
}
4.2 索引構建
// 添加文檔到索引
func (idx *InvertedIndex) AddDocument(docID int, text string) {
// 簡單的分詞(實際應用中需要更復雜的分詞算法)words := strings.Fields(strings.ToLower(text))
for pos, word := range words {if idx.Index[word] == nil {idx.Index[word] = &InvertedIndexItem{
Term: word,
DocFreq: 0,
Postings: make([]Posting, 0),
}
}
// 查找是否已存在該文檔的 posting
var posting *Posting
for i := range idx.Index[word].Postings {if idx.Index[word].Postings[i].DocID == docID {posting = &idx.Index[word].Postings[i]
break
}
}
if posting == nil {
// 創建新的 posting
newPosting := Posting{
DocID: docID,
Frequency: 1,
Positions: []int{pos},
}
idx.Index[word].Postings = append(idx.Index[word].Postings, newPosting)
idx.Index[word].DocFreq++
} else {
// 更新現有 posting
posting.Frequency++
posting.Positions = append(posting.Positions, pos)
}
}
}
4.3 查詢實現
// 單詞查詢
func (idx *InvertedIndex) Search(term string) []int {term = strings.ToLower(term)
if item, exists := idx.Index[term]; exists {docIDs := make([]int, len(item.Postings))
for i, posting := range item.Postings {docIDs[i] = posting.DocID
}
return docIDs
}
return []int{}
}
// 多詞查詢(AND 操作)func (idx *InvertedIndex) SearchAnd(terms []string) []int {if len(terms) == 0 {return []int{}}
// 獲取第一個詞的結果
result := idx.Search(terms[0])
// 與其他詞的結果求交集
for i := 1; i < len(terms); i++ {otherResult := idx.Search(terms[i])
result = intersect(result, otherResult)
}
return result
}
// 多詞查詢(OR 操作)func (idx *InvertedIndex) SearchOr(terms []string) []int {if len(terms) == 0 {return []int{}}
resultSet := make(map[int]bool)
for _, term := range terms {docIDs := idx.Search(term)
for _, docID := range docIDs {resultSet[docID] = true
}
}
result := make([]int, 0, len(resultSet))
for docID := range resultSet {result = append(result, docID)
}
sort.Ints(result)
return result
}
// 求兩個切片的交集
func intersect(a, b []int) []int {set := make(map[int]bool)
for _, x := range a {set[x] = true
}
result := make([]int, 0)
for _, x := range b {if set[x] {result = append(result, x)
}
}
return result
}
4.4 完整示例
func main() {
// 創建倒排索引
index := NewInvertedIndex()
// 添加文檔
documents := []Document{{ID: 1, Text: "Go is a programming language"},
{ID: 2, Text: "Go is fast and efficient"},
{ID: 3, Text: "Programming in Go is fun"},
{ID: 4, Text: "Go language is simple"},
}
// 構建索引
for _, doc := range documents {index.AddDocument(doc.ID, doc.Text)
}
// 查詢示例
fmt.Println(" 搜索 'go':", index.Search("go"))
fmt.Println(" 搜索 'programming':", index.Search("programming"))
fmt.Println(" 搜索 'go' AND 'language':", index.SearchAnd([]string{"go", "language"}))
fmt.Println(" 搜索 'go' OR 'fast':", index.SearchOr([]string{"go", "fast"}))
// 打印索引結構
fmt.Println("\n 倒排索引結構:")
for term, item := range index.Index {fmt.Printf(" 詞項: %s, 文檔頻率: %d\n", term, item.DocFreq)
for _, posting := range item.Postings {
fmt.Printf(" 文檔 ID: %d, 詞頻: %d, 位置: %v\n",
posting.DocID, posting.Frequency, posting.Positions)
}
}
}
5. 倒排索引的優化
5.1 壓縮技術
- 變長編碼 :使用變長編碼壓縮文檔 ID
- 差分編碼 :存儲文檔 ID 的差值而不是絕對值
- 位圖壓縮 :使用位圖表示文檔集合
5.2 查詢優化
- 跳躍表 :在長列表中快速定位
- 緩存機制 :緩存熱門查詢結果
- 並行查詢 :多線程處理查詢
6. 實際應用場景
6.1 搜索引擎
- Google、百度等搜索引擎的核心技術
- 網頁內容索引和檢索
6.2 數據庫系統
- 全文搜索功能
- 文本字段的快速查詢
6.3 代碼搜索
- GitHub 代碼搜索
- IDE 中的代碼導航
6.4 日誌分析
- 日誌文件的快速檢索
- 錯誤日誌的定位
7. 性能分析
7.1 時間複雜度
- 構建索引 :O(N×M),N 爲文檔數,M 爲平均詞數
- 單詞查詢 :O(1) 平均情況
- 多詞查詢 :O(k×log(n)),k 爲結果數,n 爲文檔數
7.2 空間複雜度
- 存儲空間 :O(V×D),V 爲詞彙量,D 爲平均文檔頻率
7.3 優缺點
優點 :
- 查詢速度快
- 支持複雜查詢
- 易於實現
缺點 :
- 構建索引耗時
- 存儲空間較大
- 更新索引複雜
8. 總結
倒排索引是信息檢索領域的核心技術,通過將 ” 文檔 - 詞 ” 的關係倒轉爲 ” 詞 - 文檔 ” 的關係,實現了高效的文本搜索。在 Go 語言中,我們可以使用 map 和切片等基本數據結構來實現倒排索引,爲應用程序提供強大的搜索功能。
multi_match 使用說明
multi_match 是 ES 中在多個字段上同時進行搜索的查詢類型,本質上是對 match 查詢在多字段上的擴展。適合標題、描述、標籤等多個文本字段聯合檢索,常配合字段權重、不同查詢類型與分詞器使用。
1. 基本用法
POST /index/_search
{
"query": {
"multi_match": {
"query": "iPhone 15",
"fields": ["title", "description", "tags"]
}
}
}
2. 字段權重(boost)
POST /index/_search
{
"query": {
"multi_match": {
"query": "iPhone 15",
"fields": ["title^3", "description^1.5", "tags"]
}
}
}
說明:title^3 表示爲 title 字段的匹配結果乘以 3 的權重,從而在排序時提升該字段命中結果的分數。
3. type 選項與適用場景
- best_fields(默認):在所有字段中挑選最匹配的字段分數作爲主分數,可配合
tie_breaker
POST /index/_search
{
"query": {
"multi_match": {
"query": "apple phone",
"fields": ["title", "description", "tags"],
"type": "best_fields",
"tie_breaker": 0.2
}
}
}
- most_fields:多個字段得分疊加,適合同一語義分佈在多個字段的情況(如同一文本拆分存儲在不同字段)
POST /index/_search
{
"query": {
"multi_match": {
"query": "iphone",
"fields": ["title", "title.ngram", "description"],
"type": "most_fields"
}
}
}
- cross_fields:將多個字段當作一個大字段進行匹配,適合將詞語分佈在不同字段的場景(如 first_name + last_name)
POST /index/_search
{
"query": {
"multi_match": {
"query": "tim cook",
"fields": ["first_name", "last_name"],
"type": "cross_fields",
"operator": "and"
}
}
}
- phrase:短語匹配,要求詞序與距離嚴格,適合精確短語搜索
POST /index/_search
{
"query": {
"multi_match": {
"query": "iphone 15 pro",
"fields": ["title", "description"],
"type": "phrase"
}
}
}
- phrase_prefix:短語前綴匹配,適合輸入法聯想 / 搜索建議
POST /index/_search
{
"query": {
"multi_match": {
"query": "iph 15",
"fields": ["title", "description"],
"type": "phrase_prefix",
"max_expansions": 50
}
}
}
4. 操作符與最小匹配
POST /index/_search
{
"query": {
"multi_match": {
"query": "apple flagship phone",
"fields": ["title", "description"],
"operator": "and",
"minimum_should_match": "75%"
}
}
}
說明:
operator: and要求查詢詞全部匹配;or(默認)爲匹配任意一個minimum_should_match控制最少匹配詞的比例或數量,如2、3<75%、75%等
5. 模糊匹配(fuzziness)與糾錯
POST /index/_search
{
"query": {
"multi_match": {
"query": "iphine",
"fields": ["title", "description"],
"fuzziness": "AUTO",
"prefix_length": 1
}
}
}
說明:fuzziness: AUTO 對常見拼寫錯誤具備容錯能力;prefix_length 指定前綴必須精確匹配的長度。
6. 分詞器與字段選擇
POST /index/_search
{
"query": {
"multi_match": {
"query": " 蘋果 手機 ",
"fields": ["title", "title.keyword^5", "description"],
"analyzer": "ik_smart"
}
}
}
建議:
- 多用於
text字段進行全文檢索;精確匹配與聚合 / 排序使用keyword字段(可配合 boost) - 中文檢索可使用
ik_smart、ik_max_word等分詞器(需安裝插件)
7. 組合示例(綜合字段、權重、過濾與排序)
POST /products/_search
{"_source": ["id", "title", "price", "brand"],
"from": 0,
"size": 20,
"sort": [{"_score": "desc"},
{"price": "asc"}
],
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "iphone 15 pro",
"fields": ["title^4", "subtitle^2", "description", "tags"],
"type": "best_fields",
"tie_breaker": 0.3,
"minimum_should_match": "66%"
}
}
],
"filter": [{"term": {"brand": "apple"}},
{"range": {"price": {"gte": 3000, "lte": 10000}}}
]
}
},
"highlight": {
"fields": {"title": {},
"description": {}}
}
}
8. 常見問題與建議
- 相關性不理想:
- 爲核心字段設置更高權重(如
title^N) - 選擇合適的
type:跨字段詞分佈用cross_fields,綜合得分用most_fields - 使用同義詞、拼寫糾錯(
fuzziness)與領域詞典 - 性能問題:
- 控制返回字段(
_source過濾)與size - 將過濾條件放入
filter,命中緩存且不參與評分 - 避免在巨量字段上使用
wildcard/phrase_prefix進行前綴擴展 - 精確 vs 全文:
- 精確匹配與聚合使用
keyword;全文檢索使用text+ 分詞器 - 可爲同一業務字段建
multi-fields(text+keyword)
term 查詢詳解
term 查詢是 ES 中用於精確匹配的查詢類型,不會對查詢詞進行分詞處理,直接與索引中的詞項進行精確匹配。適用於 keyword 類型字段、數值字段、日期字段等。(沒有進行分詞,小寫化處理)
1. 基本用法
POST /products/_search
{
"query": {
"term": {"status": "active"}
}
}
2. 多字段 term 查詢
POST /products/_search
{
"query": {
"bool": {
"must": [{"term": {"status": "active"}},
{"term": {"category": "electronics"}},
{"term": {"brand": "apple"}}
]
}
}
}
3. 數值字段精確匹配
POST /products/_search
{
"query": {
"term": {"price": 5999}
}
}
4. 日期字段精確匹配
POST /products/_search
{
"query": {
"term": {"created_date": "2025-01-18"}
}
}
5. 數組字段匹配
POST /products/_search
{
"query": {
"term": {"tags": "phone"}
}
}
6. 使用 boost 提升權重
POST /products/_search
{
"query": {
"term": {
"status": {
"value": "active",
"boost": 2.0
}
}
}
}
7. terms 查詢(多值匹配)
POST /products/_search
{
"query": {
"terms": {"status": ["active", "pending", "review"]
}
}
}
8. 與 filter 結合使用
POST /products/_search
{
"query": {
"bool": {
"must": [{"match": {"title": "iPhone"}}
],
"filter": [{"term": {"status": "active"}},
{"term": {"category": "electronics"}}
]
}
}
}
term vs match 查詢對比
1. 核心區別
| 特性 | term 查詢 | match 查詢 |
|---|---|---|
| 分詞處理 | 不進行分詞,精確匹配 | 對查詢詞進行分詞處理 |
| 匹配方式 | 精確匹配索引中的詞項 | 模糊匹配,支持相關性評分 |
| 適用字段 | keyword、數值、日期等 | text 類型字段 |
| 性能 | 更快(不計算相關性) | 較慢(需要計算評分) |
| 緩存 | 結果可被緩存 | 結果通常不被緩存 |
2. 實際示例對比
2.1 相同查詢詞的不同結果
# 數據準備
POST /test/_doc/1
{
"title": "iPhone 15 Pro Max",
"title.keyword": "iPhone 15 Pro Max",
"status": "active"
}
# term 查詢 - 精確匹配
POST /test/_search
{
"query": {
"term": {"title.keyword": "iPhone 15 Pro Max"}
}
}
# 結果:匹配成功
# term 查詢 - 對 text 字段使用 term(通常不匹配)POST /test/_search
{
"query": {
"term": {"title": "iPhone 15 Pro Max"}
}
}
# 結果:不匹配(因爲 title 被分詞爲 ["iphone", "15", "pro", "max"])# match 查詢 - 對 text 字段使用 match
POST /test/_search
{
"query": {
"match": {"title": "iPhone 15 Pro Max"}
}
}
# 結果:匹配成功,有相關性評分
2.2 部分匹配對比
# term 查詢 - 部分詞不匹配
POST /test/_search
{
"query": {
"term": {"title.keyword": "iPhone 15"}
}
}
# 結果:不匹配(需要完全一致)# match 查詢 - 部分詞匹配
POST /test/_search
{
"query": {
"match": {"title": "iPhone 15"}
}
}
# 結果:匹配成功,相關性評分較低
3. 使用場景對比
3.1 term 查詢適用場景
# 1. 狀態過濾
POST /products/_search
{
"query": {
"bool": {
"filter": [{"term": {"status": "active"}}
]
}
}
}
# 2. 分類篩選
POST /products/_search
{
"query": {
"bool": {
"filter": [{"term": {"category": "electronics"}}
]
}
}
}
# 3. 標籤匹配
POST /products/_search
{
"query": {
"bool": {
"filter": [{"term": {"tags": "premium"}}
]
}
}
}
# 4. 聚合統計
POST /products/_search
{
"size": 0,
"aggs": {
"status_count": {
"terms": {"field": "status"}
}
}
}
3.2 match 查詢適用場景
# 1. 全文搜索
POST /products/_search
{
"query": {
"match": {"title": "iPhone 15 Pro"}
}
}
# 2. 描述搜索
POST /products/_search
{
"query": {
"match": {"description": " 最新款手機 "}
}
}
# 3. 多字段搜索
POST /products/_search
{
"query": {
"multi_match": {
"query": " 蘋果手機 ",
"fields": ["title", "description", "tags"]
}
}
}
4. 性能對比
4.1 查詢性能
# term 查詢 - 高性能
POST /products/_search
{
"query": {
"bool": {
"filter": [{"term": {"status": "active"}},
{"term": {"category": "electronics"}}
]
}
}
}
# 特點:不計算相關性,結果可緩存
# match 查詢 - 相對較慢
POST /products/_search
{
"query": {
"bool": {
"must": [{"match": {"title": "iPhone"}},
{"match": {"description": " 手機 "}}
]
}
}
}
# 特點:需要計算相關性評分,結果通常不緩存
4.2 混合使用優化
# 最佳實踐:term 用於過濾,match 用於搜索
POST /products/_search
{
"query": {
"bool": {
"must": [{"match": {"title": "iPhone 15"}}
],
"filter": [{"term": {"status": "active"}},
{"term": {"category": "electronics"}},
{"range": {"price": {"gte": 1000, "lte": 10000}}}
]
}
}
}
5. 常見錯誤與解決方案
5.1 對 text 字段使用 term 查詢
# 錯誤用法
POST /products/_search
{
"query": {
"term": {"title": "iPhone" # title 是 text 字段,會被分詞}
}
}
# 正確用法
POST /products/_search
{
"query": {
"term": {"title.keyword": "iPhone" # 使用 keyword 字段}
}
}
# 或者使用 match
POST /products/_search
{
"query": {
"match": {"title": "iPhone"}
}
}
5.2 大小寫敏感問題
# term 查詢大小寫敏感
POST /products/_search
{
"query": {
"term": {"status": "Active" # 如果索引中是 "active",則不匹配}
}
}
# 解決方案:使用 match 或確保大小寫一致
POST /products/_search
{
"query": {
"match": {"status": "Active" # match 會進行分詞和標準化}
}
}
6. 最佳實踐建議
6.1 字段映射設計
# 創建支持兩種查詢的映射
PUT /products
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_smart",
"fields": {
"keyword": {"type": "keyword"}
}
},
"status": {"type": "keyword"},
"price": {"type": "double"}
}
}
}
6.2 查詢組合策略
# 推薦:精確過濾 + 模糊搜索
POST /products/_search
{
"query": {
"bool": {
"must": [{"match": {"title": " 用戶搜索詞 "}}
],
"filter": [{"term": {"status": "active"}},
{"term": {"category": "electronics"}},
{"range": {"price": {"gte": 1000}}}
]
}
},
"sort": [{"_score": "desc"},
{"price": "asc"}
]
}
7. 總結
- term 查詢 :適用於精確匹配、過濾、聚合,性能更好,結果可緩存
- match 查詢 :適用於全文搜索、模糊匹配,支持相關性評分
- 最佳實踐 :term 用於過濾條件,match 用於搜索內容,兩者結合使用
- 字段設計 :爲需要精確匹配的字段創建 keyword 子字段
- 性能優化 :將精確匹配條件放在 filter 中,避免不必要的評分計算
ES Mapping 概念與使用
1. 什麼是 Mapping
Mapping 是索引的“結構定義”,類似關係型數據庫的表結構 schema,用於聲明每個字段的類型與索引方式,決定:
- 字段的數據類型與存儲形式(text、keyword、numeric、date、boolean、geo、nested 等)
- 是否參與倒排索引與如何分詞(
index、analyzer) - 是否可用於聚合 / 排序(
doc_values) - 多字段定義(multi-fields):同一業務字段以多種方式建索引
- 動態字段處理策略(
dynamic)
自 ES 7 起,一個索引僅有一個 type(內部 _doc),建模直接面向“索引 + 映射”。
2. 常用字段類型與場景
text:分詞,用於全文檢索;不適合聚合 / 排序keyword:不分詞,適合精確匹配、聚合、排序;默認有doc_values- 數值與日期:
integer/long/double/date等,適合範圍過濾、聚合和排序 - 結構化:
object(同文檔扁平對象)、nested(數組中每個對象獨立建模,支持獨立子查詢) - 地理:
geo_point/geo_shape
典型 multi-fields(既要全文又要精確):
"title": {
"type": "text",
"analyzer": "ik_smart",
"fields": {"keyword": { "type": "keyword", "ignore_above": 256}
}
}
3. 創建索引並顯式設置映射
PUT /products
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1
},
"mappings": {
"dynamic": "true",
"properties": {
"title": {
"type": "text",
"analyzer": "standard",
"fields": {"keyword": { "type": "keyword", "ignore_above": 256}
}
},
"price": {"type": "double"},
"status": {"type": "keyword"},
"createdAt": {"type": "date"},
"tags": {"type": "keyword"},
"attrs": {"type": "object"},
"specs": {"type": "nested"}
}
}
}
4. 查看 / 更新映射
- 查看映射
GET /products/_mapping
- 新增字段(只能新增,不能改變已存在字段類型)
PUT /products/_mapping
{
"properties": {"brand": { "type": "keyword"}
}
}
5. 修改字段類型的正確做法(重建索引)
- 創建新索引並定義正確映射
products_v2 - 遷移數據
POST /_reindex
{"source": { "index": "products"},
"dest": {"index": "products_v2"}
}
- 用別名切換流量
POST /_aliases
{
"actions": [{ "remove": { "index": "products", "alias": "products_read"}},
{"add": { "index": "products_v2", "alias": "products_read"}}
]
}
6. 動態映射策略
"mappings": {
"dynamic": "strict",
"properties": {/* 顯式列出字段,未知字段將被拒絕 */}
}
建議在覈心索引使用 strict,避免髒數據自動推斷成錯誤類型(例如把數值當 text)。
7. 性能與實踐要點
- 只爲需要搜索 / 過濾的字段開啓
index;純展示字段可index: false - 需要聚合 / 排序的字段保持
doc_values: true(text無 doc_values) - 中文場景安裝 IK 分詞器,並在
text字段指定analyzer - 嵌套數組使用
nested,避免object造成交叉匹配 - 使用 multi-fields 同時支持全文與精確匹配
一句話:Mapping 決定“字段如何被存、被索引、被查”,建索引前先明確查詢與聚合需求,再設計映射,才能拿到正確且高性能的檢索效果。
ES Analyzer(分詞器)使用與說明
1. 什麼是 Analyzer
Analyzer 是寫入 / 搜索時對文本字段進行“標準化 → 分詞 → 過濾”的組件,通常由三部分組成:
char_filter:字符級預處理(如去掉 HTML 標籤)tokenizer:將文本切分爲 token(詞元),如standard、whitespace、ik_smartfilter:對 token 再加工(小寫化、去停用詞、同義詞、詞幹提取等)
寫入階段使用字段的 analyzer,搜索階段默認使用同一個 analyzer,可通過 search_analyzer 單獨指定。
2. 內置常用 Analyzer
standard(默認):通用英文分詞,小寫化simple:按非字母切分,小寫化whitespace:僅按空白切分,不改變大小寫stop:在simple基礎上去停用詞keyword:不分詞,整體作爲一個 token(多用於 normalizer 對 keyword 字段)pattern:基於正則表達式分割
中文常用:需要安裝插件的 ik_smart、ik_max_word。
3. 使用 _analyze 測試分詞效果
POST /_analyze
{
"analyzer": "standard",
"text": "iPhone 15 Pro Max"
}
POST /_analyze
{
"analyzer": "ik_smart",
"text": " 蘋果手機保護殼 "
}
4. 字段上設置 analyzer 與 search_analyzer
PUT /docs
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_smart",
"search_analyzer": "ik_max_word"
}
}
}
}
說明:
- 寫入時使用
ik_smart,查詢時使用更細粒度的ik_max_word提升召回。
5. 查詢時臨時指定 analyzer(不改映射)
POST /docs/_search
{
"query": {
"match": {
"title": {
"query": " 蘋果手機 ",
"analyzer": "ik_max_word"
}
}
}
}
6. 自定義 Analyzer(含同義詞 / 停用詞)
PUT /articles
{
"settings": {
"analysis": {
"filter": {
"my_synonyms": {
"type": "synonym",
"synonyms": ["iphone, 蘋果手機 ", "notebook, 筆記本 "]
}
},
"analyzer": {
"my_zh_analyzer": {
"type": "custom",
"char_filter": ["html_strip"],
"tokenizer": "ik_smart",
"filter": ["lowercase", "my_synonyms"]
}
}
}
},
"mappings": {
"properties": {"content": { "type": "text", "analyzer": "my_zh_analyzer"}
}
}
}
7. Normalizer(針對 keyword 的標準化)
keyword 字段不分詞,無法使用 analyzer;若需大小寫歸一、去標點,可使用 normalizer:
PUT /users
{
"settings": {
"analysis": {
"normalizer": {
"lowercase_normalizer": {
"type": "custom",
"filter": ["lowercase"]
}
}
}
},
"mappings": {
"properties": {"email": { "type": "keyword", "normalizer": "lowercase_normalizer"}
}
}
}
8. IK 分詞器安裝與字段示例(簡要)
- 安裝(根據版本):
bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/...重啓 ES - 使用:
PUT /goods
{
"mappings": {
"properties": {"title": { "type": "text", "analyzer": "ik_smart", "search_analyzer": "ik_max_word"}
}
}
}
9. 變更 analyzer 的注意事項
- 已存在字段的 analyzer 基本不可直接修改;需走“重建索引(reindex)”流程
- 不同 analyzer 會影響倒排索引結構,變更後注意重新驗證查詢語義與相關性
10. 性能與實踐
- 選擇儘可能簡單的寫入分詞器(如
ik_smart),查詢端更細粒度(ik_max_word)提升召回 - 用
_analyze驗證分詞是否符合預期;頻繁的過濾條件應使用keyword+ normalizer - 控制字段數量與分詞粒度,避免索引爆炸;同義詞表外置管理便於更新
ES 術語與專有名詞速查(Glossary)
以下概念按主題歸類,便於快速理解與查閱。
索引與文檔建模
- Index(索引):文檔集合的邏輯容器,類似數據庫的庫。內部由多個分片組成
- Document(文檔):一條記錄,以 JSON 存儲,通過
_id唯一標識 - Field(字段):文檔屬性,決定了可用的查詢與聚合方式
- Mapping(映射):字段類型與索引策略的定義,等同表結構 schema
- Type:6.x 及以下存在的邏輯“表”概念。7.x 起固定
_doc,8.x 對外隱藏 - Text:會分詞的字段類型,用於全文檢索,不適合聚合 / 排序
- Keyword:不分詞,適合精確匹配、聚合 / 排序,通常有
doc_values - Multi-fields:同一字段以多種方式建索引,如
title與title.keyword - Object:對象字段,屬性扁平合併到同一文檔
- Nested:嵌套對象,每個數組元素獨立索引,避免交叉匹配,可獨立子查詢
- Dynamic mapping:未知字段出現時的策略(true/false/strict)
分詞與標準化
- Analyzer:分詞器,含
char_filter→tokenizer→filter三階段 - Tokenizer:切分爲 token 的組件,如
standard、whitespace、ik_smart - Token(詞元 / 項):倒排索引中的基本單位
- Char filter:字符級預處理,如
html_strip - Token filter:對 token 再加工,如
lowercase、synonym、stop - Normalizer:面向
keyword的標準化(小寫化、去重音等),不分詞
倒排索引與評分
- Inverted index(倒排索引):term → 文檔列表(postings)的索引結構
- Term:索引中的詞項(已標準化 / 分詞後的 token)
- Posting:文檔出現信息,包含 docID、頻次、位置等
- Relevance score:相關性評分,用於排序
- BM25:默認相關性模型(取代 TF-IDF)
- Query vs Filter:Query 參與評分,Filter 只做布爾過濾且可緩存
- Bool query:
must/should/must_not/filter組合查詢
存儲與段(Segment)
- Segment:不可變數據段,寫入追加產生;合併(merge)減少段數
- Refresh:將內存中的增量刷新爲新段,默認週期 1s,刷新後可見
- Flush:將 translog 持久化並創建新的提交點(commit)
- Translog:寫入日誌,用於崩潰恢復
- Doc values:列式存儲,支撐聚合 / 排序 / 腳本,
text無 doc values - _source:原始 JSON 文檔,默認存儲,用於重取與 reindex
- Stored fields:單獨存儲的字段(不常用),與
_source區分 - Norms:字段級長度歸一化等評分因子,可關閉以省空間
集羣與分片
- Cluster:由多個節點組成的 ES 集羣
- Node:集羣中的實例,常見角色:
master、data、ingest、coordinating - Shard(主分片):索引的物理分片單位,創建時確定數量
- Replica(副本):主分片的拷貝,提升高可用與查詢吞吐
- Routing:根據路由值決定文檔落在哪個主分片,默認基於
_idhash - Alias:別名,可指向一個或多個索引,便於無縫切換
寫入與批處理
- Bulk API:批量寫入 / 更新 / 刪除
- Update by query:按條件批量更新
- Delete by query:按條件批量刪除
- Reindex:從源索引複製到目標索引(常用於變更映射)
- Ingest pipeline:寫入前處理管道(grok、rename、set、script 等)
- Painless:ES 內置腳本語言,用於腳本更新、腳本排序等
搜索與分頁
- Match:全文查詢,會分詞
- Term/Terms:精確匹配,不分詞
- Range:範圍查詢(數值 / 日期)
- Multi-match:多字段全文查詢
- Nested query:對
nested字段的子查詢 - Aggregation:聚合分析(terms、stats、date_histogram、range 等)
- Highlight:高亮顯示命中片段
- Suggesters:搜索建議(term/phrase/completion)
- From/size:基礎分頁,深分頁代價高
- Search after:遊標式分頁,替代深分頁
- Scroll:大批量導出快照式遊標,非實時查詢
- PIT(Point in time):時間點一致性快照,用於穩定分頁
生命週期與索引管理
- ILM(Index Lifecycle Management):熱 / 溫 / 冷 / 刪 生命週期策略
- Rollover:基於大小 / 文檔數 / 時間切換新索引
- Snapshot/Restore:快照與恢復(倉庫可對接 S3、HDFS 等)
運維與性能
- Cluster health:集羣健康(green/yellow/red)
- Refresh interval:刷新週期,寫多場景可調大以提速寫入
- Replicas:副本數影響查詢吞吐與寫入成本
- Force merge:對只讀索引合併段,減少文件數提高查詢性能
- Slow logs:慢查詢與慢索引日誌,用於排障與優化
以上術語覆蓋 ES 日常建模、寫入、檢索、聚合與運維優化的高頻概念,結合前文 Mapping、Analyzer、term/match 與 multi_match 等章節,可形成完整的 ES 使用知識圖譜。