1use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
8pub struct Field(pub u32);
9
10#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12pub enum FieldType {
13 #[serde(rename = "text")]
15 Text,
16 #[serde(rename = "u64")]
18 U64,
19 #[serde(rename = "i64")]
21 I64,
22 #[serde(rename = "f64")]
24 F64,
25 #[serde(rename = "bytes")]
27 Bytes,
28 #[serde(rename = "sparse_vector")]
30 SparseVector,
31 #[serde(rename = "dense_vector")]
33 DenseVector,
34 #[serde(rename = "json")]
36 Json,
37 #[serde(rename = "binary_dense_vector")]
39 BinaryDenseVector,
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct FieldEntry {
45 pub name: String,
46 pub field_type: FieldType,
47 pub indexed: bool,
48 pub stored: bool,
49 pub tokenizer: Option<String>,
51 #[serde(default)]
53 pub multi: bool,
54 #[serde(default, skip_serializing_if = "Option::is_none")]
56 pub positions: Option<PositionMode>,
57 #[serde(default, skip_serializing_if = "Option::is_none")]
59 pub sparse_vector_config: Option<crate::structures::SparseVectorConfig>,
60 #[serde(default, skip_serializing_if = "Option::is_none")]
62 pub dense_vector_config: Option<DenseVectorConfig>,
63 #[serde(default, skip_serializing_if = "Option::is_none")]
65 pub binary_dense_vector_config: Option<BinaryDenseVectorConfig>,
66 #[serde(default)]
69 pub fast: bool,
70 #[serde(default)]
72 pub primary_key: bool,
73 #[serde(default)]
77 pub reorder: bool,
78}
79
80#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
82#[serde(rename_all = "snake_case")]
83pub enum PositionMode {
84 Ordinal,
87 TokenPosition,
90 Full,
93}
94
95impl PositionMode {
96 pub fn tracks_ordinal(&self) -> bool {
98 matches!(self, PositionMode::Ordinal | PositionMode::Full)
99 }
100
101 pub fn tracks_token_position(&self) -> bool {
103 matches!(self, PositionMode::TokenPosition | PositionMode::Full)
104 }
105}
106
107#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
109#[serde(rename_all = "snake_case")]
110pub enum VectorIndexType {
111 Flat,
113 #[default]
115 RaBitQ,
116 IvfRaBitQ,
118 ScaNN,
120}
121
122#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
128#[serde(rename_all = "snake_case")]
129pub enum DenseVectorQuantization {
130 #[default]
132 F32,
133 F16,
135 UInt8,
137 Binary,
140}
141
142impl DenseVectorQuantization {
143 pub fn element_size(self) -> usize {
146 match self {
147 Self::F32 => 4,
148 Self::F16 => 2,
149 Self::UInt8 => 1,
150 Self::Binary => panic!("element_size() not valid for Binary; use dim.div_ceil(8)"),
151 }
152 }
153
154 pub fn tag(self) -> u8 {
156 match self {
157 Self::F32 => 0,
158 Self::F16 => 1,
159 Self::UInt8 => 2,
160 Self::Binary => 3,
161 }
162 }
163
164 pub fn from_tag(tag: u8) -> Option<Self> {
166 match tag {
167 0 => Some(Self::F32),
168 1 => Some(Self::F16),
169 2 => Some(Self::UInt8),
170 3 => Some(Self::Binary),
171 _ => None,
172 }
173 }
174}
175
176#[derive(Debug, Clone, Serialize, Deserialize)]
184pub struct DenseVectorConfig {
185 pub dim: usize,
187 #[serde(default)]
190 pub index_type: VectorIndexType,
191 #[serde(default)]
193 pub quantization: DenseVectorQuantization,
194 #[serde(default, skip_serializing_if = "Option::is_none")]
197 pub num_clusters: Option<usize>,
198 #[serde(default = "default_nprobe")]
200 pub nprobe: usize,
201 #[serde(default, skip_serializing_if = "Option::is_none")]
205 pub build_threshold: Option<usize>,
206 #[serde(default = "default_unit_norm")]
211 pub unit_norm: bool,
212 #[serde(default, skip_serializing_if = "Option::is_none")]
218 pub rabitq_bits: Option<u8>,
219 #[serde(default, skip_serializing_if = "Option::is_none")]
224 pub soar: Option<crate::structures::SoarConfig>,
225}
226
227fn default_nprobe() -> usize {
228 32
229}
230
231fn default_unit_norm() -> bool {
232 true
233}
234
235impl DenseVectorConfig {
236 pub fn new(dim: usize) -> Self {
237 Self {
238 dim,
239 index_type: VectorIndexType::RaBitQ,
240 quantization: DenseVectorQuantization::F32,
241 num_clusters: None,
242 nprobe: 32,
243 build_threshold: None,
244 unit_norm: true,
245 soar: None,
246 rabitq_bits: None,
247 }
248 }
249
250 pub fn with_ivf(dim: usize, num_clusters: Option<usize>, nprobe: usize) -> Self {
252 Self {
253 dim,
254 index_type: VectorIndexType::IvfRaBitQ,
255 quantization: DenseVectorQuantization::F32,
256 num_clusters,
257 nprobe,
258 build_threshold: None,
259 unit_norm: true,
260 soar: None,
261 rabitq_bits: None,
262 }
263 }
264
265 pub fn with_scann(dim: usize, num_clusters: Option<usize>, nprobe: usize) -> Self {
267 Self {
268 dim,
269 index_type: VectorIndexType::ScaNN,
270 quantization: DenseVectorQuantization::F32,
271 num_clusters,
272 nprobe,
273 build_threshold: None,
274 unit_norm: true,
275 soar: None,
276 rabitq_bits: None,
277 }
278 }
279
280 pub fn flat(dim: usize) -> Self {
282 Self {
283 dim,
284 index_type: VectorIndexType::Flat,
285 quantization: DenseVectorQuantization::F32,
286 num_clusters: None,
287 nprobe: 0,
288 build_threshold: None,
289 unit_norm: true,
290 soar: None,
291 rabitq_bits: None,
292 }
293 }
294
295 pub fn with_quantization(mut self, quantization: DenseVectorQuantization) -> Self {
297 self.quantization = quantization;
298 self
299 }
300
301 pub fn with_build_threshold(mut self, threshold: usize) -> Self {
303 self.build_threshold = Some(threshold);
304 self
305 }
306
307 pub fn with_unit_norm(mut self) -> Self {
309 self.unit_norm = true;
310 self
311 }
312
313 pub fn with_num_clusters(mut self, num_clusters: usize) -> Self {
315 self.num_clusters = Some(num_clusters);
316 self
317 }
318
319 pub fn with_rabitq_bits(mut self, bits: u8) -> Self {
321 self.rabitq_bits = Some(bits.clamp(1, 8));
322 self
323 }
324
325 pub fn with_soar(mut self, soar: crate::structures::SoarConfig) -> Self {
327 self.soar = Some(soar);
328 self
329 }
330
331 pub fn uses_ivf(&self) -> bool {
333 matches!(
334 self.index_type,
335 VectorIndexType::IvfRaBitQ | VectorIndexType::ScaNN
336 )
337 }
338
339 pub fn uses_scann(&self) -> bool {
341 self.index_type == VectorIndexType::ScaNN
342 }
343
344 pub fn is_flat(&self) -> bool {
346 self.index_type == VectorIndexType::Flat
347 }
348
349 pub fn default_build_threshold(&self) -> usize {
351 self.build_threshold.unwrap_or(match self.index_type {
352 VectorIndexType::Flat => usize::MAX, VectorIndexType::RaBitQ => 1000,
354 VectorIndexType::IvfRaBitQ | VectorIndexType::ScaNN => 10000,
355 })
356 }
357
358 pub fn optimal_num_clusters(&self, num_vectors: usize) -> usize {
360 self.num_clusters.unwrap_or_else(|| {
361 let optimal = (num_vectors as f64).sqrt() as usize;
363 optimal.clamp(16, 4096)
364 })
365 }
366}
367
368#[derive(Debug, Clone, Serialize, Deserialize)]
374pub struct BinaryDenseVectorConfig {
375 pub dim: usize,
377 #[serde(default)]
381 pub index_type: BinaryIndexType,
382 #[serde(default, skip_serializing_if = "Option::is_none")]
384 pub num_clusters: Option<usize>,
385 #[serde(default = "default_nprobe")]
387 pub nprobe: usize,
388 #[serde(default, skip_serializing_if = "Option::is_none")]
391 pub build_threshold: Option<usize>,
392}
393
394#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
396#[serde(rename_all = "snake_case")]
397pub enum BinaryIndexType {
398 #[default]
400 Flat,
401 Ivf,
403}
404
405impl BinaryDenseVectorConfig {
406 pub fn new(dim: usize) -> Self {
407 assert!(
408 dim.is_multiple_of(8),
409 "BinaryDenseVector dimension must be a multiple of 8, got {dim}"
410 );
411 Self {
412 dim,
413 index_type: BinaryIndexType::Flat,
414 num_clusters: None,
415 nprobe: 32,
416 build_threshold: None,
417 }
418 }
419
420 pub fn with_ivf(mut self, num_clusters: Option<usize>, nprobe: usize) -> Self {
422 self.index_type = BinaryIndexType::Ivf;
423 self.num_clusters = num_clusters;
424 self.nprobe = nprobe;
425 self
426 }
427
428 pub fn with_build_threshold(mut self, threshold: usize) -> Self {
430 self.build_threshold = Some(threshold);
431 self
432 }
433
434 pub fn default_build_threshold(&self) -> usize {
436 self.build_threshold.unwrap_or(100_000)
437 }
438
439 pub fn optimal_num_clusters(&self, num_vectors: usize) -> usize {
441 self.num_clusters.unwrap_or_else(|| {
442 let optimal = (num_vectors as f64).sqrt() as usize;
443 optimal.clamp(16, 4096)
444 })
445 }
446
447 pub fn byte_len(&self) -> usize {
449 self.dim.div_ceil(8)
450 }
451}
452
453use super::query_field_router::QueryRouterRule;
454
455#[derive(Debug, Clone, Default, Serialize, Deserialize)]
457pub struct Schema {
458 fields: Vec<FieldEntry>,
459 name_to_field: HashMap<String, Field>,
460 #[serde(default)]
462 default_fields: Vec<Field>,
463 #[serde(default)]
465 query_routers: Vec<QueryRouterRule>,
466 #[serde(default)]
471 reorder_on_merge: bool,
472 #[serde(default)]
476 index_name: String,
477}
478
479impl Schema {
480 pub fn builder() -> SchemaBuilder {
481 SchemaBuilder::default()
482 }
483
484 pub fn get_field(&self, name: &str) -> Option<Field> {
485 self.name_to_field.get(name).copied()
486 }
487
488 pub fn get_field_entry(&self, field: Field) -> Option<&FieldEntry> {
489 self.fields.get(field.0 as usize)
490 }
491
492 pub fn get_field_name(&self, field: Field) -> Option<&str> {
493 self.fields.get(field.0 as usize).map(|e| e.name.as_str())
494 }
495
496 pub fn fields(&self) -> impl Iterator<Item = (Field, &FieldEntry)> {
497 self.fields
498 .iter()
499 .enumerate()
500 .map(|(i, e)| (Field(i as u32), e))
501 }
502
503 pub fn num_fields(&self) -> usize {
504 self.fields.len()
505 }
506
507 pub fn has_reorder_fields(&self) -> bool {
510 self.fields.iter().any(|e| e.reorder)
511 }
512
513 pub fn reorder_on_merge(&self) -> bool {
516 self.reorder_on_merge
517 }
518
519 pub fn index_label(&self) -> &str {
522 if self.index_name.is_empty() {
523 "unknown"
524 } else {
525 &self.index_name
526 }
527 }
528
529 pub fn set_index_name(&mut self, name: impl Into<String>) {
531 self.index_name = name.into();
532 }
533
534 pub fn default_fields(&self) -> &[Field] {
536 &self.default_fields
537 }
538
539 pub fn set_default_fields(&mut self, fields: Vec<Field>) {
541 self.default_fields = fields;
542 }
543
544 pub fn query_routers(&self) -> &[QueryRouterRule] {
546 &self.query_routers
547 }
548
549 pub fn set_query_routers(&mut self, rules: Vec<QueryRouterRule>) {
551 self.query_routers = rules;
552 }
553
554 pub fn primary_field(&self) -> Option<Field> {
556 self.fields
557 .iter()
558 .enumerate()
559 .find(|(_, e)| e.primary_key)
560 .map(|(i, _)| Field(i as u32))
561 }
562}
563
564#[derive(Debug, Default)]
566pub struct SchemaBuilder {
567 fields: Vec<FieldEntry>,
568 default_fields: Vec<String>,
569 query_routers: Vec<QueryRouterRule>,
570 reorder_on_merge: bool,
571 index_name: String,
572}
573
574impl SchemaBuilder {
575 pub fn add_text_field(&mut self, name: &str, indexed: bool, stored: bool) -> Field {
576 self.add_field_with_tokenizer(
577 name,
578 FieldType::Text,
579 indexed,
580 stored,
581 Some("simple".to_string()),
582 )
583 }
584
585 pub fn add_text_field_with_tokenizer(
586 &mut self,
587 name: &str,
588 indexed: bool,
589 stored: bool,
590 tokenizer: &str,
591 ) -> Field {
592 self.add_field_with_tokenizer(
593 name,
594 FieldType::Text,
595 indexed,
596 stored,
597 Some(tokenizer.to_string()),
598 )
599 }
600
601 pub fn add_u64_field(&mut self, name: &str, indexed: bool, stored: bool) -> Field {
602 self.add_field(name, FieldType::U64, indexed, stored)
603 }
604
605 pub fn add_i64_field(&mut self, name: &str, indexed: bool, stored: bool) -> Field {
606 self.add_field(name, FieldType::I64, indexed, stored)
607 }
608
609 pub fn add_f64_field(&mut self, name: &str, indexed: bool, stored: bool) -> Field {
610 self.add_field(name, FieldType::F64, indexed, stored)
611 }
612
613 pub fn add_bytes_field(&mut self, name: &str, stored: bool) -> Field {
614 self.add_field(name, FieldType::Bytes, false, stored)
615 }
616
617 pub fn add_json_field(&mut self, name: &str, stored: bool) -> Field {
622 self.add_field(name, FieldType::Json, false, stored)
623 }
624
625 pub fn add_sparse_vector_field(&mut self, name: &str, indexed: bool, stored: bool) -> Field {
630 self.add_sparse_vector_field_with_config(
631 name,
632 indexed,
633 stored,
634 crate::structures::SparseVectorConfig::default(),
635 )
636 }
637
638 pub fn add_sparse_vector_field_with_config(
643 &mut self,
644 name: &str,
645 indexed: bool,
646 stored: bool,
647 config: crate::structures::SparseVectorConfig,
648 ) -> Field {
649 let field = Field(self.fields.len() as u32);
650 self.fields.push(FieldEntry {
651 name: name.to_string(),
652 field_type: FieldType::SparseVector,
653 indexed,
654 stored,
655 tokenizer: None,
656 multi: false,
657 positions: None,
658 sparse_vector_config: Some(config),
659 dense_vector_config: None,
660 binary_dense_vector_config: None,
661 fast: false,
662 primary_key: false,
663 reorder: false,
664 });
665 field
666 }
667
668 pub fn set_sparse_vector_config(
670 &mut self,
671 field: Field,
672 config: crate::structures::SparseVectorConfig,
673 ) {
674 if let Some(entry) = self.fields.get_mut(field.0 as usize) {
675 entry.sparse_vector_config = Some(config);
676 }
677 }
678
679 pub fn add_dense_vector_field(
684 &mut self,
685 name: &str,
686 dim: usize,
687 indexed: bool,
688 stored: bool,
689 ) -> Field {
690 self.add_dense_vector_field_with_config(name, indexed, stored, DenseVectorConfig::new(dim))
691 }
692
693 pub fn add_dense_vector_field_with_config(
695 &mut self,
696 name: &str,
697 indexed: bool,
698 stored: bool,
699 config: DenseVectorConfig,
700 ) -> Field {
701 let field = Field(self.fields.len() as u32);
702 self.fields.push(FieldEntry {
703 name: name.to_string(),
704 field_type: FieldType::DenseVector,
705 indexed,
706 stored,
707 tokenizer: None,
708 multi: false,
709 positions: None,
710 sparse_vector_config: None,
711 dense_vector_config: Some(config),
712 binary_dense_vector_config: None,
713 fast: false,
714 primary_key: false,
715 reorder: false,
716 });
717 field
718 }
719
720 pub fn add_binary_dense_vector_field(
725 &mut self,
726 name: &str,
727 dim: usize,
728 indexed: bool,
729 stored: bool,
730 ) -> Field {
731 self.add_binary_dense_vector_field_with_config(
732 name,
733 indexed,
734 stored,
735 BinaryDenseVectorConfig::new(dim),
736 )
737 }
738
739 pub fn add_binary_dense_vector_field_with_config(
741 &mut self,
742 name: &str,
743 indexed: bool,
744 stored: bool,
745 config: BinaryDenseVectorConfig,
746 ) -> Field {
747 let field = Field(self.fields.len() as u32);
748 self.fields.push(FieldEntry {
749 name: name.to_string(),
750 field_type: FieldType::BinaryDenseVector,
751 indexed,
752 stored,
753 tokenizer: None,
754 multi: false,
755 positions: None,
756 sparse_vector_config: None,
757 dense_vector_config: None,
758 binary_dense_vector_config: Some(config),
759 fast: false,
760 primary_key: false,
761 reorder: false,
762 });
763 field
764 }
765
766 fn add_field(
767 &mut self,
768 name: &str,
769 field_type: FieldType,
770 indexed: bool,
771 stored: bool,
772 ) -> Field {
773 self.add_field_with_tokenizer(name, field_type, indexed, stored, None)
774 }
775
776 fn add_field_with_tokenizer(
777 &mut self,
778 name: &str,
779 field_type: FieldType,
780 indexed: bool,
781 stored: bool,
782 tokenizer: Option<String>,
783 ) -> Field {
784 self.add_field_full(name, field_type, indexed, stored, tokenizer, false)
785 }
786
787 fn add_field_full(
788 &mut self,
789 name: &str,
790 field_type: FieldType,
791 indexed: bool,
792 stored: bool,
793 tokenizer: Option<String>,
794 multi: bool,
795 ) -> Field {
796 let field = Field(self.fields.len() as u32);
797 self.fields.push(FieldEntry {
798 name: name.to_string(),
799 field_type,
800 indexed,
801 stored,
802 tokenizer,
803 multi,
804 positions: None,
805 sparse_vector_config: None,
806 dense_vector_config: None,
807 binary_dense_vector_config: None,
808 fast: false,
809 primary_key: false,
810 reorder: false,
811 });
812 field
813 }
814
815 pub fn set_multi(&mut self, field: Field, multi: bool) {
817 if let Some(entry) = self.fields.get_mut(field.0 as usize) {
818 entry.multi = multi;
819 }
820 }
821
822 pub fn set_fast(&mut self, field: Field, fast: bool) {
825 if let Some(entry) = self.fields.get_mut(field.0 as usize) {
826 entry.fast = fast;
827 }
828 }
829
830 pub fn set_primary_key(&mut self, field: Field) {
836 if let Some(entry) = self.fields.get_mut(field.0 as usize) {
837 entry.primary_key = true;
838 entry.fast = true;
839 entry.indexed = true;
840 }
841 }
842
843 pub fn set_reorder(&mut self, field: Field, reorder: bool) {
845 if let Some(entry) = self.fields.get_mut(field.0 as usize) {
846 entry.reorder = reorder;
847 }
848 }
849
850 pub fn set_reorder_on_merge(&mut self, on: bool) {
853 self.reorder_on_merge = on;
854 }
855
856 pub fn set_index_name(&mut self, name: impl Into<String>) {
858 self.index_name = name.into();
859 }
860
861 pub fn set_positions(&mut self, field: Field, mode: PositionMode) {
863 if let Some(entry) = self.fields.get_mut(field.0 as usize) {
864 entry.positions = Some(mode);
865 }
866 }
867
868 pub fn set_default_fields(&mut self, field_names: Vec<String>) {
870 self.default_fields = field_names;
871 }
872
873 pub fn set_query_routers(&mut self, rules: Vec<QueryRouterRule>) {
875 self.query_routers = rules;
876 }
877
878 pub fn build(self) -> Schema {
879 let mut name_to_field = HashMap::new();
880 for (i, entry) in self.fields.iter().enumerate() {
881 name_to_field.insert(entry.name.clone(), Field(i as u32));
882 }
883
884 let default_fields: Vec<Field> = self
886 .default_fields
887 .iter()
888 .filter_map(|name| name_to_field.get(name).copied())
889 .collect();
890
891 Schema {
892 fields: self.fields,
893 name_to_field,
894 default_fields,
895 query_routers: self.query_routers,
896 reorder_on_merge: self.reorder_on_merge,
897 index_name: self.index_name,
898 }
899 }
900}
901
902#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
904pub enum FieldValue {
905 #[serde(rename = "text")]
906 Text(String),
907 #[serde(rename = "u64")]
908 U64(u64),
909 #[serde(rename = "i64")]
910 I64(i64),
911 #[serde(rename = "f64")]
912 F64(f64),
913 #[serde(rename = "bytes")]
914 Bytes(Vec<u8>),
915 #[serde(rename = "sparse_vector")]
917 SparseVector(Vec<(u32, f32)>),
918 #[serde(rename = "dense_vector")]
920 DenseVector(Vec<f32>),
921 #[serde(rename = "json")]
923 Json(serde_json::Value),
924 #[serde(rename = "binary_dense_vector")]
926 BinaryDenseVector(Vec<u8>),
927}
928
929impl FieldValue {
930 pub fn as_text(&self) -> Option<&str> {
931 match self {
932 FieldValue::Text(s) => Some(s),
933 _ => None,
934 }
935 }
936
937 pub fn as_u64(&self) -> Option<u64> {
938 match self {
939 FieldValue::U64(v) => Some(*v),
940 _ => None,
941 }
942 }
943
944 pub fn as_i64(&self) -> Option<i64> {
945 match self {
946 FieldValue::I64(v) => Some(*v),
947 _ => None,
948 }
949 }
950
951 pub fn as_f64(&self) -> Option<f64> {
952 match self {
953 FieldValue::F64(v) => Some(*v),
954 _ => None,
955 }
956 }
957
958 pub fn as_bytes(&self) -> Option<&[u8]> {
959 match self {
960 FieldValue::Bytes(b) => Some(b),
961 _ => None,
962 }
963 }
964
965 pub fn as_sparse_vector(&self) -> Option<&[(u32, f32)]> {
966 match self {
967 FieldValue::SparseVector(entries) => Some(entries),
968 _ => None,
969 }
970 }
971
972 pub fn as_dense_vector(&self) -> Option<&[f32]> {
973 match self {
974 FieldValue::DenseVector(v) => Some(v),
975 _ => None,
976 }
977 }
978
979 pub fn as_json(&self) -> Option<&serde_json::Value> {
980 match self {
981 FieldValue::Json(v) => Some(v),
982 _ => None,
983 }
984 }
985
986 pub fn as_binary_dense_vector(&self) -> Option<&[u8]> {
987 match self {
988 FieldValue::BinaryDenseVector(v) => Some(v),
989 _ => None,
990 }
991 }
992}
993
994#[derive(Debug, Clone, Default, Serialize, Deserialize)]
996pub struct Document {
997 field_values: Vec<(Field, FieldValue)>,
998}
999
1000impl Document {
1001 pub fn new() -> Self {
1002 Self::default()
1003 }
1004
1005 pub fn add_text(&mut self, field: Field, value: impl Into<String>) {
1006 self.field_values
1007 .push((field, FieldValue::Text(value.into())));
1008 }
1009
1010 pub fn add_u64(&mut self, field: Field, value: u64) {
1011 self.field_values.push((field, FieldValue::U64(value)));
1012 }
1013
1014 pub fn add_i64(&mut self, field: Field, value: i64) {
1015 self.field_values.push((field, FieldValue::I64(value)));
1016 }
1017
1018 pub fn add_f64(&mut self, field: Field, value: f64) {
1019 self.field_values.push((field, FieldValue::F64(value)));
1020 }
1021
1022 pub fn add_bytes(&mut self, field: Field, value: Vec<u8>) {
1023 self.field_values.push((field, FieldValue::Bytes(value)));
1024 }
1025
1026 pub fn add_sparse_vector(&mut self, field: Field, entries: Vec<(u32, f32)>) {
1027 self.field_values
1028 .push((field, FieldValue::SparseVector(entries)));
1029 }
1030
1031 pub fn add_dense_vector(&mut self, field: Field, values: Vec<f32>) {
1032 self.field_values
1033 .push((field, FieldValue::DenseVector(values)));
1034 }
1035
1036 pub fn add_json(&mut self, field: Field, value: serde_json::Value) {
1037 self.field_values.push((field, FieldValue::Json(value)));
1038 }
1039
1040 pub fn add_binary_dense_vector(&mut self, field: Field, values: Vec<u8>) {
1041 self.field_values
1042 .push((field, FieldValue::BinaryDenseVector(values)));
1043 }
1044
1045 pub fn get_first(&self, field: Field) -> Option<&FieldValue> {
1046 self.field_values
1047 .iter()
1048 .find(|(f, _)| *f == field)
1049 .map(|(_, v)| v)
1050 }
1051
1052 pub fn get_all(&self, field: Field) -> impl Iterator<Item = &FieldValue> {
1053 self.field_values
1054 .iter()
1055 .filter(move |(f, _)| *f == field)
1056 .map(|(_, v)| v)
1057 }
1058
1059 pub fn field_values(&self) -> &[(Field, FieldValue)] {
1060 &self.field_values
1061 }
1062
1063 pub fn filter_stored(&self, schema: &Schema) -> Document {
1065 Document {
1066 field_values: self
1067 .field_values
1068 .iter()
1069 .filter(|(field, _)| {
1070 schema
1071 .get_field_entry(*field)
1072 .is_some_and(|entry| entry.stored)
1073 })
1074 .cloned()
1075 .collect(),
1076 }
1077 }
1078
1079 pub fn to_json(&self, schema: &Schema) -> serde_json::Value {
1085 use std::collections::HashMap;
1086
1087 let mut field_values_map: HashMap<Field, (String, bool, Vec<serde_json::Value>)> =
1089 HashMap::new();
1090
1091 for (field, value) in &self.field_values {
1092 if let Some(entry) = schema.get_field_entry(*field) {
1093 let json_value = match value {
1094 FieldValue::Text(s) => serde_json::Value::String(s.clone()),
1095 FieldValue::U64(n) => serde_json::Value::Number((*n).into()),
1096 FieldValue::I64(n) => serde_json::Value::Number((*n).into()),
1097 FieldValue::F64(n) => serde_json::json!(n),
1098 FieldValue::Bytes(b) => {
1099 use base64::Engine;
1100 serde_json::Value::String(
1101 base64::engine::general_purpose::STANDARD.encode(b),
1102 )
1103 }
1104 FieldValue::SparseVector(entries) => {
1105 let indices: Vec<u32> = entries.iter().map(|(i, _)| *i).collect();
1106 let values: Vec<f32> = entries.iter().map(|(_, v)| *v).collect();
1107 serde_json::json!({
1108 "indices": indices,
1109 "values": values
1110 })
1111 }
1112 FieldValue::DenseVector(values) => {
1113 serde_json::json!(values)
1114 }
1115 FieldValue::Json(v) => v.clone(),
1116 FieldValue::BinaryDenseVector(b) => {
1117 use base64::Engine;
1118 serde_json::Value::String(
1119 base64::engine::general_purpose::STANDARD.encode(b),
1120 )
1121 }
1122 };
1123 field_values_map
1124 .entry(*field)
1125 .or_insert_with(|| (entry.name.clone(), entry.multi, Vec::new()))
1126 .2
1127 .push(json_value);
1128 }
1129 }
1130
1131 let mut map = serde_json::Map::new();
1133 for (_field, (name, is_multi, values)) in field_values_map {
1134 let json_value = if is_multi || values.len() > 1 {
1135 serde_json::Value::Array(values)
1136 } else {
1137 values.into_iter().next().unwrap()
1138 };
1139 map.insert(name, json_value);
1140 }
1141
1142 serde_json::Value::Object(map)
1143 }
1144
1145 pub fn from_json(json: &serde_json::Value, schema: &Schema) -> Option<Self> {
1154 let obj = json.as_object()?;
1155 let mut doc = Document::new();
1156
1157 for (key, value) in obj {
1158 if let Some(field) = schema.get_field(key) {
1159 let field_entry = schema.get_field_entry(field)?;
1160 Self::add_json_value(&mut doc, field, &field_entry.field_type, value);
1161 }
1162 }
1163
1164 Some(doc)
1165 }
1166
1167 fn add_json_value(
1169 doc: &mut Document,
1170 field: Field,
1171 field_type: &FieldType,
1172 value: &serde_json::Value,
1173 ) {
1174 match value {
1175 serde_json::Value::String(s) => {
1176 if matches!(field_type, FieldType::Text) {
1177 doc.add_text(field, s.clone());
1178 }
1179 }
1180 serde_json::Value::Number(n) => {
1181 match field_type {
1182 FieldType::I64 => {
1183 if let Some(i) = n.as_i64() {
1184 doc.add_i64(field, i);
1185 }
1186 }
1187 FieldType::U64 => {
1188 if let Some(u) = n.as_u64() {
1189 doc.add_u64(field, u);
1190 } else if let Some(i) = n.as_i64() {
1191 if i >= 0 {
1193 doc.add_u64(field, i as u64);
1194 }
1195 }
1196 }
1197 FieldType::F64 => {
1198 if let Some(f) = n.as_f64() {
1199 doc.add_f64(field, f);
1200 }
1201 }
1202 _ => {}
1203 }
1204 }
1205 serde_json::Value::Array(arr) => {
1207 for item in arr {
1208 Self::add_json_value(doc, field, field_type, item);
1209 }
1210 }
1211 serde_json::Value::Object(obj) if matches!(field_type, FieldType::SparseVector) => {
1213 if let (Some(indices_val), Some(values_val)) =
1214 (obj.get("indices"), obj.get("values"))
1215 {
1216 let indices: Vec<u32> = indices_val
1217 .as_array()
1218 .map(|arr| {
1219 arr.iter()
1220 .filter_map(|v| v.as_u64().map(|n| n as u32))
1221 .collect()
1222 })
1223 .unwrap_or_default();
1224 let values: Vec<f32> = values_val
1225 .as_array()
1226 .map(|arr| {
1227 arr.iter()
1228 .filter_map(|v| v.as_f64().map(|n| n as f32))
1229 .collect()
1230 })
1231 .unwrap_or_default();
1232 if indices.len() == values.len() {
1233 let entries: Vec<(u32, f32)> = indices.into_iter().zip(values).collect();
1234 doc.add_sparse_vector(field, entries);
1235 }
1236 }
1237 }
1238 _ if matches!(field_type, FieldType::Json) => {
1240 doc.add_json(field, value.clone());
1241 }
1242 serde_json::Value::Object(_) => {}
1243 _ => {}
1244 }
1245 }
1246}
1247
1248#[cfg(test)]
1249mod tests {
1250 use super::*;
1251
1252 #[test]
1253 fn test_schema_builder() {
1254 let mut builder = Schema::builder();
1255 let title = builder.add_text_field("title", true, true);
1256 let body = builder.add_text_field("body", true, false);
1257 let count = builder.add_u64_field("count", true, true);
1258 let schema = builder.build();
1259
1260 assert_eq!(schema.get_field("title"), Some(title));
1261 assert_eq!(schema.get_field("body"), Some(body));
1262 assert_eq!(schema.get_field("count"), Some(count));
1263 assert_eq!(schema.get_field("nonexistent"), None);
1264 }
1265
1266 #[test]
1267 fn test_set_primary_key_forces_fast_and_indexed() {
1268 let mut builder = Schema::builder();
1273 let id = builder.add_text_field("id", false, true);
1274 builder.set_primary_key(id);
1275 let schema = builder.build();
1276
1277 let entry = schema.get_field_entry(id).unwrap();
1278 assert!(entry.primary_key);
1279 assert!(
1280 entry.fast,
1281 "primary key must imply fast (dedup reads the fast-field text dict)"
1282 );
1283 assert!(entry.indexed, "primary key must imply indexed");
1284 }
1285
1286 #[test]
1287 fn test_document() {
1288 let mut builder = Schema::builder();
1289 let title = builder.add_text_field("title", true, true);
1290 let count = builder.add_u64_field("count", true, true);
1291 let _schema = builder.build();
1292
1293 let mut doc = Document::new();
1294 doc.add_text(title, "Hello World");
1295 doc.add_u64(count, 42);
1296
1297 assert_eq!(doc.get_first(title).unwrap().as_text(), Some("Hello World"));
1298 assert_eq!(doc.get_first(count).unwrap().as_u64(), Some(42));
1299 }
1300
1301 #[test]
1302 fn test_document_serialization() {
1303 let mut builder = Schema::builder();
1304 let title = builder.add_text_field("title", true, true);
1305 let count = builder.add_u64_field("count", true, true);
1306 let _schema = builder.build();
1307
1308 let mut doc = Document::new();
1309 doc.add_text(title, "Hello World");
1310 doc.add_u64(count, 42);
1311
1312 let json = serde_json::to_string(&doc).unwrap();
1314 println!("Serialized doc: {}", json);
1315
1316 let doc2: Document = serde_json::from_str(&json).unwrap();
1318 assert_eq!(
1319 doc2.field_values().len(),
1320 2,
1321 "Should have 2 field values after deserialization"
1322 );
1323 assert_eq!(
1324 doc2.get_first(title).unwrap().as_text(),
1325 Some("Hello World")
1326 );
1327 assert_eq!(doc2.get_first(count).unwrap().as_u64(), Some(42));
1328 }
1329
1330 #[test]
1331 fn test_multivalue_field() {
1332 let mut builder = Schema::builder();
1333 let uris = builder.add_text_field("uris", true, true);
1334 let title = builder.add_text_field("title", true, true);
1335 let schema = builder.build();
1336
1337 let mut doc = Document::new();
1339 doc.add_text(uris, "one");
1340 doc.add_text(uris, "two");
1341 doc.add_text(title, "Test Document");
1342
1343 assert_eq!(doc.get_first(uris).unwrap().as_text(), Some("one"));
1345
1346 let all_uris: Vec<_> = doc.get_all(uris).collect();
1348 assert_eq!(all_uris.len(), 2);
1349 assert_eq!(all_uris[0].as_text(), Some("one"));
1350 assert_eq!(all_uris[1].as_text(), Some("two"));
1351
1352 let json = doc.to_json(&schema);
1354 let uris_json = json.get("uris").unwrap();
1355 assert!(uris_json.is_array(), "Multi-value field should be an array");
1356 let uris_arr = uris_json.as_array().unwrap();
1357 assert_eq!(uris_arr.len(), 2);
1358 assert_eq!(uris_arr[0].as_str(), Some("one"));
1359 assert_eq!(uris_arr[1].as_str(), Some("two"));
1360
1361 let title_json = json.get("title").unwrap();
1363 assert!(
1364 title_json.is_string(),
1365 "Single-value field should be a string"
1366 );
1367 assert_eq!(title_json.as_str(), Some("Test Document"));
1368 }
1369
1370 #[test]
1371 fn test_multivalue_from_json() {
1372 let mut builder = Schema::builder();
1373 let uris = builder.add_text_field("uris", true, true);
1374 let title = builder.add_text_field("title", true, true);
1375 let schema = builder.build();
1376
1377 let json = serde_json::json!({
1379 "uris": ["one", "two"],
1380 "title": "Test Document"
1381 });
1382
1383 let doc = Document::from_json(&json, &schema).unwrap();
1385
1386 let all_uris: Vec<_> = doc.get_all(uris).collect();
1388 assert_eq!(all_uris.len(), 2);
1389 assert_eq!(all_uris[0].as_text(), Some("one"));
1390 assert_eq!(all_uris[1].as_text(), Some("two"));
1391
1392 assert_eq!(
1394 doc.get_first(title).unwrap().as_text(),
1395 Some("Test Document")
1396 );
1397
1398 let json_out = doc.to_json(&schema);
1400 let uris_out = json_out.get("uris").unwrap().as_array().unwrap();
1401 assert_eq!(uris_out.len(), 2);
1402 assert_eq!(uris_out[0].as_str(), Some("one"));
1403 assert_eq!(uris_out[1].as_str(), Some("two"));
1404 }
1405
1406 #[test]
1407 fn test_multi_attribute_forces_array() {
1408 let mut builder = Schema::builder();
1411 let uris = builder.add_text_field("uris", true, true);
1412 builder.set_multi(uris, true); let title = builder.add_text_field("title", true, true);
1414 let schema = builder.build();
1415
1416 assert!(schema.get_field_entry(uris).unwrap().multi);
1418 assert!(!schema.get_field_entry(title).unwrap().multi);
1419
1420 let mut doc = Document::new();
1422 doc.add_text(uris, "only_one");
1423 doc.add_text(title, "Test Document");
1424
1425 let json = doc.to_json(&schema);
1427
1428 let uris_json = json.get("uris").unwrap();
1429 assert!(
1430 uris_json.is_array(),
1431 "Multi field should be array even with single value"
1432 );
1433 let uris_arr = uris_json.as_array().unwrap();
1434 assert_eq!(uris_arr.len(), 1);
1435 assert_eq!(uris_arr[0].as_str(), Some("only_one"));
1436
1437 let title_json = json.get("title").unwrap();
1439 assert!(
1440 title_json.is_string(),
1441 "Non-multi single-value field should be a string"
1442 );
1443 assert_eq!(title_json.as_str(), Some("Test Document"));
1444 }
1445
1446 #[test]
1447 fn test_sparse_vector_field() {
1448 let mut builder = Schema::builder();
1449 let embedding = builder.add_sparse_vector_field("embedding", true, true);
1450 let title = builder.add_text_field("title", true, true);
1451 let schema = builder.build();
1452
1453 assert_eq!(schema.get_field("embedding"), Some(embedding));
1454 assert_eq!(
1455 schema.get_field_entry(embedding).unwrap().field_type,
1456 FieldType::SparseVector
1457 );
1458
1459 let mut doc = Document::new();
1461 doc.add_sparse_vector(embedding, vec![(0, 1.0), (5, 2.5), (10, 0.5)]);
1462 doc.add_text(title, "Test Document");
1463
1464 let entries = doc
1466 .get_first(embedding)
1467 .unwrap()
1468 .as_sparse_vector()
1469 .unwrap();
1470 assert_eq!(entries, &[(0, 1.0), (5, 2.5), (10, 0.5)]);
1471
1472 let json = doc.to_json(&schema);
1474 let embedding_json = json.get("embedding").unwrap();
1475 assert!(embedding_json.is_object());
1476 assert_eq!(
1477 embedding_json
1478 .get("indices")
1479 .unwrap()
1480 .as_array()
1481 .unwrap()
1482 .len(),
1483 3
1484 );
1485
1486 let doc2 = Document::from_json(&json, &schema).unwrap();
1488 let entries2 = doc2
1489 .get_first(embedding)
1490 .unwrap()
1491 .as_sparse_vector()
1492 .unwrap();
1493 assert_eq!(entries2[0].0, 0);
1494 assert!((entries2[0].1 - 1.0).abs() < 1e-6);
1495 assert_eq!(entries2[1].0, 5);
1496 assert!((entries2[1].1 - 2.5).abs() < 1e-6);
1497 assert_eq!(entries2[2].0, 10);
1498 assert!((entries2[2].1 - 0.5).abs() < 1e-6);
1499 }
1500
1501 #[test]
1502 fn test_json_field() {
1503 let mut builder = Schema::builder();
1504 let metadata = builder.add_json_field("metadata", true);
1505 let title = builder.add_text_field("title", true, true);
1506 let schema = builder.build();
1507
1508 assert_eq!(schema.get_field("metadata"), Some(metadata));
1509 assert_eq!(
1510 schema.get_field_entry(metadata).unwrap().field_type,
1511 FieldType::Json
1512 );
1513 assert!(!schema.get_field_entry(metadata).unwrap().indexed);
1515 assert!(schema.get_field_entry(metadata).unwrap().stored);
1516
1517 let json_value = serde_json::json!({
1519 "author": "John Doe",
1520 "tags": ["rust", "search"],
1521 "nested": {"key": "value"}
1522 });
1523 let mut doc = Document::new();
1524 doc.add_json(metadata, json_value.clone());
1525 doc.add_text(title, "Test Document");
1526
1527 let stored_json = doc.get_first(metadata).unwrap().as_json().unwrap();
1529 assert_eq!(stored_json, &json_value);
1530 assert_eq!(
1531 stored_json.get("author").unwrap().as_str(),
1532 Some("John Doe")
1533 );
1534
1535 let doc_json = doc.to_json(&schema);
1537 let metadata_out = doc_json.get("metadata").unwrap();
1538 assert_eq!(metadata_out, &json_value);
1539
1540 let doc2 = Document::from_json(&doc_json, &schema).unwrap();
1542 let stored_json2 = doc2.get_first(metadata).unwrap().as_json().unwrap();
1543 assert_eq!(stored_json2, &json_value);
1544 }
1545
1546 #[test]
1547 fn test_json_field_various_types() {
1548 let mut builder = Schema::builder();
1549 let data = builder.add_json_field("data", true);
1550 let _schema = builder.build();
1551
1552 let arr_value = serde_json::json!([1, 2, 3, "four", null]);
1554 let mut doc = Document::new();
1555 doc.add_json(data, arr_value.clone());
1556 assert_eq!(doc.get_first(data).unwrap().as_json().unwrap(), &arr_value);
1557
1558 let str_value = serde_json::json!("just a string");
1560 let mut doc2 = Document::new();
1561 doc2.add_json(data, str_value.clone());
1562 assert_eq!(doc2.get_first(data).unwrap().as_json().unwrap(), &str_value);
1563
1564 let num_value = serde_json::json!(42.5);
1566 let mut doc3 = Document::new();
1567 doc3.add_json(data, num_value.clone());
1568 assert_eq!(doc3.get_first(data).unwrap().as_json().unwrap(), &num_value);
1569
1570 let null_value = serde_json::Value::Null;
1572 let mut doc4 = Document::new();
1573 doc4.add_json(data, null_value.clone());
1574 assert_eq!(
1575 doc4.get_first(data).unwrap().as_json().unwrap(),
1576 &null_value
1577 );
1578
1579 let bool_value = serde_json::json!(true);
1581 let mut doc5 = Document::new();
1582 doc5.add_json(data, bool_value.clone());
1583 assert_eq!(
1584 doc5.get_first(data).unwrap().as_json().unwrap(),
1585 &bool_value
1586 );
1587 }
1588}