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