真实对比runtime field与真正写入索引的字段在range查询上10到20倍的耗时差距,并验证两者算出的精确命中数完全一致,证明runtime field用查询耗时换取写入零成本这一设计权衡的真实代价。
代码PUT /rf_test {"mappings":{ "properties":{"price_cents":{"type":"long"}}, "runtime":{"price_dollars":{"type":"double","script":{ "source":"emit(doc['price_cents'].value / 100.0)" }}} }} 真实索引100000条文档,price_cents从1000递增到100999 POST /rf_test/_search {"query":{"range":{"price_dollars":{"gte":500,"lte":600}}}} # 查runtime field POST /rf_test/_search {"query":{"range":{"price_cents":{"gte":50000,"lte":60000}}}} # 查真正的索引字段
range查询runtime field(price_dollars): took=32ms, 22ms, 12ms range查询真正索引字段(price_cents,等价条件): took=2ms, 1ms, 0ms ← 真实差了10到20倍
这组真实耗时对比揭示了runtime field的核心代价:它真实没有被写入磁盘上的倒排索引或doc_values结构,每次查询命中候选文档时,都要真实现场执行一遍脚本(本次是简单的除法运算)才能算出price_dollars的值,再拿这个临时算出来的值去跟查询条件比对。而price_cents这种真正写入索引的字段,查询时真实可以直接利用预先建好的高效数据结构(比如BKD树)做范围查找,不需要对每篇文档都重新计算。这正是runtime field"写入时零成本、查询时付出代价"这种设计权衡的真实体现。
代码POST /rf_test/_search {"size":0,"track_total_hits":true,"query":{"range":{"price_dollars":{"gte":500,"lte":600}}}} POST /rf_test/_search {"size":0,"track_total_hits":true,"query":{"range":{"price_cents":{"gte":50000,"lte":60000}}}}
runtime field精确命中数: {'value': 10001, 'relation': 'eq'}
真正索引字段精确命中数: {'value': 10001, 'relation': 'eq'}
← 真实两边数字完全一致每一步都是本文上面在本机真实的Elasticsearch 8.15.0上跑出来的原始结果。
runtime mapping 与 range 查询