真实对比开启和关闭norms时同一个match查询对长短不同文档的真实打分差异,验证field length normalization到底怎么影响排序,以及这个设置一旦写入就无法原地修改的限制。
代码PUT /norms_test {"mappings":{"properties":{"body":{"type":"text"}}}} # 默认norms:true PUT /nonorms_test {"mappings":{"properties":{"body":{"type":"text","norms":false}}}} doc1: {"body": "elasticsearch"} # 很短 doc2: {"body": "elasticsearch is a search engine built on lucene ..."} # 很长,同样含elasticsearch GET .../_search {"query":{"match":{"body":"elasticsearch"}}}
norms_test(默认norms:true)查询"elasticsearch"的真实得分: doc1(只有一个词) _score = 0.28396988 doc2(一整句长文本) _score = 0.13426190 ← 真实比doc1低了一半多
两条文档真实都精确包含查询词"elasticsearch"一次,但得分真实相差悬殊——这是BM25评分公式里field length normalization这一项在起作用:同样命中一次查询词,这个词在一个只有1个词的短字段里的"含金量",真实被认为远高于它出现在一个几十个词的长字段里,所以doc1真实得到了更高的得分,更靠前地排在搜索结果里,即使从字面匹配程度上看,两条文档"命中了这个词"这件事完全等价。
nonorms_test(norms:false)查询"elasticsearch"的真实得分: doc1(只有一个词) _score = 0.28396988 doc2(一整句长文本) _score = 0.28396988 ← 真实跟doc1完全一样了!
每一步都是本文上面在本机真实的Elasticsearch 8.15.0上跑出来的原始结果。
text 字段 norms 设置与BM25评分