nodedb_fts/index/
fieldnorm.rs1use nodedb_types::Surrogate;
10
11use crate::backend::FtsBackend;
12use crate::codec::smallfloat;
13use crate::index::FtsIndex;
14
15impl<B: FtsBackend> FtsIndex<B> {
16 pub fn read_fieldnorm(
20 &self,
21 database_id: u64,
22 tid: u64,
23 collection: &str,
24 doc_id: Surrogate,
25 ) -> Result<Option<u32>, B::Error> {
26 let data = self
27 .backend
28 .read_meta(database_id, tid, collection, "fieldnorms")?;
29 match data {
30 Some(bytes) if (doc_id.0 as usize) < bytes.len() => {
31 Ok(Some(smallfloat::decode(bytes[doc_id.0 as usize])))
32 }
33 _ => Ok(None),
34 }
35 }
36
37 pub fn write_fieldnorm(
39 &self,
40 database_id: u64,
41 tid: u64,
42 collection: &str,
43 doc_id: Surrogate,
44 doc_length: u32,
45 ) -> Result<(), B::Error> {
46 let mut data = self
47 .backend
48 .read_meta(database_id, tid, collection, "fieldnorms")?
49 .unwrap_or_default();
50
51 let idx = doc_id.0 as usize;
52 if idx >= data.len() {
53 data.resize(idx + 1, 0);
54 }
55 data[idx] = smallfloat::encode(doc_length);
56
57 self.backend
58 .write_meta(database_id, tid, collection, "fieldnorms", &data)
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use nodedb_types::Surrogate;
65
66 use crate::backend::memory::MemoryBackend;
67 use crate::codec::smallfloat;
68 use crate::index::FtsIndex;
69
70 const DB: u64 = 0;
71 const T: u64 = 1;
72
73 #[test]
74 fn fieldnorm_roundtrip() {
75 let idx = FtsIndex::new(MemoryBackend::new());
76 idx.write_fieldnorm(DB, T, "col", Surrogate(0), 100)
77 .unwrap();
78 idx.write_fieldnorm(DB, T, "col", Surrogate(5), 50).unwrap();
79
80 let norm0 = idx
81 .read_fieldnorm(DB, T, "col", Surrogate(0))
82 .unwrap()
83 .unwrap();
84 let norm5 = idx
85 .read_fieldnorm(DB, T, "col", Surrogate(5))
86 .unwrap()
87 .unwrap();
88
89 assert!(norm0 <= 100);
90 assert!(norm5 <= 50);
91 assert_eq!(norm0, smallfloat::decode(smallfloat::encode(100)));
92 assert_eq!(norm5, smallfloat::decode(smallfloat::encode(50)));
93 }
94
95 #[test]
96 fn fieldnorm_missing_doc() {
97 let idx = FtsIndex::new(MemoryBackend::new());
98 assert_eq!(
99 idx.read_fieldnorm(DB, T, "col", Surrogate(99)).unwrap(),
100 None
101 );
102 }
103
104 #[test]
105 fn fieldnorm_overwrite() {
106 let idx = FtsIndex::new(MemoryBackend::new());
107 idx.write_fieldnorm(DB, T, "col", Surrogate(0), 100)
108 .unwrap();
109 idx.write_fieldnorm(DB, T, "col", Surrogate(0), 200)
110 .unwrap();
111
112 let norm = idx
113 .read_fieldnorm(DB, T, "col", Surrogate(0))
114 .unwrap()
115 .unwrap();
116 assert_eq!(norm, smallfloat::decode(smallfloat::encode(200)));
117 }
118}