查詢的倒排索引
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 使用知識圖譜。
主題測試文章,只做測試使用。發佈者:Walker,轉轉請注明出處:https://walker-learn.xyz/archives/4784