日誌系統使用 Elasticsearch,映射中 ip 欄位類型為 long。實際資料為 "127.0.0.1" 格式字串,寫入時拋出 NumberFormatException。需將類型改為 ip (ES 5.0+) 或 keyword/text。
PUT /store/client/_mapping
{
"client": {
"properties": {
"local_ip": { "type": "string", "store": "yes" }
}
}
}
報錯:MergeMappingException: mapper [local_ip] of different type, current_type [long], merged_type [string]
「You can't change existing mapping type, you need to create a new index with the correct mapping and reindex the data.」
底層 Lucene Segment 不可變,修改類型必須重建索引 (Reindex)。
PUT /store_v2
{
"settings": { "number_of_shards": 20 },
"mappings": {
"client": {
"properties": {
"ip": { "type": "ip" }, // 或 "keyword"
"cost": { "type": "long" }
}
}
}
}
應用程式始終寫入/查詢 store alias,切換索引時只需更新 alias 指向,無需改代碼。
# Python pyes 範例
import pyes
conn = pyes.ES("https://10.x.x.x:9200/")
# 掃描舊索引
search = pyes.query.MatchAllQuery().search(scroll="30m", size=1000)
hits = conn.search(search, index='store_v1', doc_type='client', scan=True)
for hit in hits:
conn.index(hit['_source'], 'store_v2', 'client', hit['_id'], bulk=True)
conn.flush()
耗時約 1 小時完成歷史資料同步。增量資料若一致性要求不高可暫忽略,或配合 Logstash/Beats 雙寫。
POST /_aliases
{
"actions": [
{ "remove": { "alias": "store", "index": "store_v1" }},
{ "add": { "alias": "store", "index": "store_v2" }}
]
}
DELETE /store_v1。POST /_reindex 內建支援跨索引複製,無需外部腳本。Elasticsearch Mapping 類型一旦建立即不可變,修改需重建索引。善用 Alias 實現零停機切換,配合 Reindex API 或 Scroll+Bulk 遷移資料,是標準運維流程。雖過程稍繁瑣,但保障了資料一致性與查詢效能。