文章目錄
- 背景
- 問題1,Filesystem Cache 里放的是啥
- 問題2,哪些查詢它們會受益于文件系統緩存
- 問題3 查詢分析
背景
對于es 優化來說常常看到會有一條結論給,給 JVM Heap 最多不超過物理內存的 50%,且不要超過 31GB(避免壓縮指針失效)。剩下的內存盡量留給操作系統做文件系統緩存。es查詢重度依賴
Filesystem Cache。
問題1,Filesystem Cache 里放的是啥
文件系統緩存保存的是什么?
文件系統緩存由操作系統管理,而不是 Elasticsearch。
它緩存的是從磁盤讀取的文件內容,比如 Lucene 構建的倒排索引文件(segment files)。
這些文件包括:
.fnm (field names)
.tim / .tip (term index and dictionary)
.doc / .pos / .pay (document values, positions, payloads)
.dvd / .dvm (doc values)
等等。
這些數據構成了 Elasticsearch 實現快速全文檢索的核心結構 —— 倒排索引(Inverted Index)
問題2,哪些查詢它們會受益于文件系統緩存
以下是一些典型的查詢類型和場景,它們會受益于文件系統緩存:
🔹1. Term 查詢 / Term-level 查詢
示例:精確匹配某個字段值
{"query": {"term": {"status": "published"}}
}
解釋:
term 查詢會查找包含特定 term 的文檔。
Lucene 使用 .tim(Term Index) 和 .tip(Term Dictionary) 文件快速定位 term。
如果這些文件已經在文件系統緩存中,則完全不需要磁盤 I/O。
🔹2. Terms 查詢
示例:匹配多個枚舉值
{"query": {"terms": {"category": ["books", "electronics", "movies"]}}
}
解釋:
多個 term 的組合查詢。
每個 term 都會在倒排索引中查找對應的文檔列表。
只要 .tim, .tip, .doc, .pos 等文件都在緩存中,性能非常高。
🔹3. Range 查詢(數值或時間范圍)
示例:查詢某段時間內的訂單
{"query": {"range": {"timestamp": {"gte": "2024-01-01","lt": "2025-01-01"}}}
}
解釋:
如果字段是 keyword 或已經構建了 doc values(.dvm, .dvd),Lucene 會利用排序結構進行快速范圍掃描。
如果相關 segment 的 .dvd 文件在緩存中,范圍查詢非常高效。
🔹4. Filter 上下文中的查詢(Query in Filter Context)
示例:
{
"query": {"bool": {"filter": [{ "term": { "status": "published" } },{ "range": { "price": { "gte": 100, "lt": 500 } } }]}}
}
解釋:
filter 上下文不計算相關度分數,只關心是否匹配。
Lucene 會使用 bitset 來加速 filter 查詢,如果索引文件已在緩存中,速度極快。
filter 查詢非常適合利用緩存,因為結果可重復使用(適合 cache)。
🔹5. 聚合查詢(Aggregations)
示例:按 category 分組統計數量
{"size": 0,"aggs": {"categories": {"terms": { "field": "category.keyword" }}}
}
解釋:
聚合操作需要遍歷大量文檔,讀取字段值。
如果字段是 keyword 類型,Lucene 使用全局序號(global ordinals)和 .gob 文件進行處理。
如果這些文件在緩存中,聚合速度非常快,否則會觸發大量磁盤讀取。
🔹6. Doc value 字段查詢
示例:
{"query": {"range": {"price": {"gte": 100,"lt": 500}}}
}
解釋:
如果 price 字段開啟了 doc_values(默認開啟),Lucene 使用 .dvd 和 .dvm 文件來存儲列式數據。
這些文件會被操作系統緩存在內存中,所以范圍查詢、排序、聚合等都非常快。
🔹7. 前綴查詢(Prefix Query)
示例:
{"query": {"prefix": {"name": "elasti"}}
}
問題3 查詢分析
- 如果_source 是true的話,要先查系統緩存,找到文檔ID ,再查磁盤找到原始文件
- 如果返回的是部分字段?
下面我們詳細解釋每種方式的工作原理。
🔍 一、使用 _source filtering(源過濾)
這是最常見的方法,適用于你只想返回原始文檔中的某些字段。
示例:
json
{"_source": {"includes": ["title", "author"]},"query": {"term": {"status": "published"}}
}
工作流程:
Elasticsearch 仍然會從 .source 文件中加載整個原始文檔。
然后在內存中進行字段過濾,只保留你需要的字段。
最終只返回這些字段給客戶端。
💡 關鍵點:
即使你只要幾個字段,Elasticsearch 仍需要加載完整 _source。
如果 .source 文件不在文件系統緩存中,就會觸發磁盤 I/O。
所以:雖然減少了網絡傳輸量,但沒有減少磁盤訪問。
🔍 二、使用 store: true 的 stored fields(存儲字段)
如果你只需要少量字段,并希望快速獲取它們而不需要加載整個 _source,可以在 mapping 中為某些字段設置 store: true。
示例 mapping:
json
{"mappings": {"properties": {"title": { "type": "text", "store": true },"author": { "type": "keyword", "store": true },"content": { "type": "text" } // 默認不存儲}}
}
查詢時:
json
{"stored_fields": ["title", "author"],"source": false,"query": {"term": {"status": "published"}}
}
工作流程:
Elasticsearch 從 Lucene 的 .fdt / .fdx 文件中讀取存儲字段(stored fields)。
這些文件是獨立于 _source 的。
如果這些文件在文件系統緩存中,查詢速度非常快。
💡 關鍵點:
沒有加載 _source,所以節省了內存和磁盤 I/O。
更適合“高頻訪問 + 字段少”的場景。
缺點是:占用更多磁盤空間 ,因為每個字段都單獨存儲了一份。
🔍 三、使用 docvalue_fields(適合聚合/排序)
對于 keyword 類型或數值類型字段,Lucene 使用 doc values 來支持高效的排序和聚合。
示例:
{"docvalue_fields": ["price", "publish_date"],"source": false,"query": {"term": {"status": "published"}}
}
工作流程:
Elasticsearch 從 .dvd, .dvm 文件中讀取字段值。
這些文件也是列式存儲,非常適合批量讀取。
如果這些文件在緩存中,性能非常高。
💡 關鍵點:
完全不依賴 _source。
對聚合、排序、范圍查詢非常有用。
不適合返回大量文本內容(如文章正文)。