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]
116 IvfPq,
117}
118
119#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
125#[serde(rename_all = "snake_case")]
126pub enum IvfRoutingMode {
127 #[default]
130 Auto,
131 Flat,
133 TwoLevel,
135 Hnsw,
137}
138
139#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
145#[serde(rename_all = "snake_case")]
146pub enum DenseVectorQuantization {
147 #[default]
149 F32,
150 F16,
152 UInt8,
154 Binary,
157}
158
159impl DenseVectorQuantization {
160 pub fn element_size(self) -> usize {
163 match self {
164 Self::F32 => 4,
165 Self::F16 => 2,
166 Self::UInt8 => 1,
167 Self::Binary => panic!("element_size() not valid for Binary; use dim.div_ceil(8)"),
168 }
169 }
170
171 pub fn tag(self) -> u8 {
173 match self {
174 Self::F32 => 0,
175 Self::F16 => 1,
176 Self::UInt8 => 2,
177 Self::Binary => 3,
178 }
179 }
180
181 pub fn from_tag(tag: u8) -> Option<Self> {
183 match tag {
184 0 => Some(Self::F32),
185 1 => Some(Self::F16),
186 2 => Some(Self::UInt8),
187 3 => Some(Self::Binary),
188 _ => None,
189 }
190 }
191}
192
193#[derive(Debug, Clone, Serialize, Deserialize)]
203pub struct DenseVectorConfig {
204 pub dim: usize,
206 #[serde(default)]
209 pub index_type: VectorIndexType,
210 #[serde(default)]
212 pub quantization: DenseVectorQuantization,
213 #[serde(default, skip_serializing_if = "Option::is_none")]
217 pub num_clusters: Option<usize>,
218 #[serde(default)]
221 pub ivf_routing: IvfRoutingMode,
222 #[serde(default = "default_nprobe")]
224 pub nprobe: usize,
225 #[serde(default = "default_unit_norm")]
230 pub unit_norm: bool,
231 #[serde(default, skip_serializing_if = "Option::is_none")]
236 pub soar: Option<crate::structures::SoarConfig>,
237}
238
239fn default_nprobe() -> usize {
240 64
241}
242
243fn default_unit_norm() -> bool {
244 true
245}
246
247impl DenseVectorConfig {
248 pub fn new(dim: usize) -> Self {
249 Self {
250 dim,
251 index_type: VectorIndexType::IvfPq,
252 quantization: DenseVectorQuantization::F32,
253 num_clusters: None,
254 ivf_routing: IvfRoutingMode::Auto,
255 nprobe: 64,
256 unit_norm: true,
257 soar: None,
258 }
259 }
260
261 pub fn with_ivf_pq(dim: usize, num_clusters: Option<usize>, nprobe: usize) -> Self {
263 Self {
264 dim,
265 index_type: VectorIndexType::IvfPq,
266 quantization: DenseVectorQuantization::F32,
267 num_clusters,
268 ivf_routing: IvfRoutingMode::Auto,
269 nprobe,
270 unit_norm: true,
271 soar: None,
272 }
273 }
274
275 pub fn flat(dim: usize) -> Self {
277 Self {
278 dim,
279 index_type: VectorIndexType::Flat,
280 quantization: DenseVectorQuantization::F32,
281 num_clusters: None,
282 ivf_routing: IvfRoutingMode::Auto,
283 nprobe: 0,
284 unit_norm: true,
285 soar: None,
286 }
287 }
288
289 pub fn with_quantization(mut self, quantization: DenseVectorQuantization) -> Self {
291 self.quantization = quantization;
292 self
293 }
294
295 pub fn with_unit_norm(mut self) -> Self {
297 self.unit_norm = true;
298 self
299 }
300
301 pub fn with_num_clusters(mut self, num_clusters: usize) -> Self {
303 self.num_clusters = Some(num_clusters);
304 self
305 }
306
307 pub fn with_ivf_routing(mut self, routing: IvfRoutingMode) -> Self {
309 self.ivf_routing = routing;
310 self
311 }
312 pub fn with_soar(mut self, soar: crate::structures::SoarConfig) -> Self {
314 self.soar = Some(soar);
315 self
316 }
317
318 pub fn uses_ivf(&self) -> bool {
320 self.index_type == VectorIndexType::IvfPq
321 }
322
323 pub fn is_flat(&self) -> bool {
325 self.index_type == VectorIndexType::Flat
326 }
327
328 pub fn optimal_num_clusters(&self, num_vectors: usize) -> usize {
330 self.num_clusters.unwrap_or_else(|| {
331 let optimal = 8.0 * (num_vectors as f64).sqrt();
335 (optimal as usize).clamp(16, 1_048_576)
336 })
337 }
338}
339
340#[derive(Debug, Clone, Serialize, Deserialize)]
346pub struct BinaryDenseVectorConfig {
347 pub dim: usize,
349 #[serde(default)]
353 pub index_type: BinaryIndexType,
354 #[serde(default, skip_serializing_if = "Option::is_none")]
356 pub num_clusters: Option<usize>,
357 #[serde(default)]
360 pub ivf_routing: IvfRoutingMode,
361 #[serde(default = "default_nprobe")]
363 pub nprobe: usize,
364}
365
366#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
368#[serde(rename_all = "snake_case")]
369pub enum BinaryIndexType {
370 Flat,
372 #[default]
374 Ivf,
375}
376
377impl BinaryDenseVectorConfig {
378 pub fn new(dim: usize) -> Self {
379 assert!(
380 dim.is_multiple_of(8),
381 "BinaryDenseVector dimension must be a multiple of 8, got {dim}"
382 );
383 Self {
384 dim,
385 index_type: BinaryIndexType::Ivf,
386 num_clusters: None,
387 ivf_routing: IvfRoutingMode::Auto,
388 nprobe: 64,
389 }
390 }
391
392 pub fn with_ivf(mut self, num_clusters: Option<usize>, nprobe: usize) -> Self {
394 self.index_type = BinaryIndexType::Ivf;
395 self.num_clusters = num_clusters;
396 self.nprobe = nprobe;
397 self
398 }
399
400 pub fn with_ivf_routing(mut self, routing: IvfRoutingMode) -> Self {
402 self.ivf_routing = routing;
403 self
404 }
405
406 pub fn optimal_num_clusters(&self, num_vectors: usize) -> usize {
408 self.num_clusters.unwrap_or_else(|| {
409 let optimal = 8.0 * (num_vectors as f64).sqrt();
410 (optimal as usize).clamp(16, 1_048_576)
411 })
412 }
413
414 pub fn byte_len(&self) -> usize {
416 self.dim.div_ceil(8)
417 }
418}
419
420use super::query_field_router::QueryRouterRule;
421
422#[derive(Debug, Clone, Default, Serialize, Deserialize)]
424pub struct Schema {
425 fields: Vec<FieldEntry>,
426 name_to_field: HashMap<String, Field>,
427 #[serde(default)]
429 default_fields: Vec<Field>,
430 #[serde(default)]
432 query_routers: Vec<QueryRouterRule>,
433 #[serde(default)]
438 reorder_on_merge: bool,
439 #[serde(default)]
443 index_name: String,
444}
445
446impl Schema {
447 pub fn builder() -> SchemaBuilder {
448 SchemaBuilder::default()
449 }
450
451 pub fn get_field(&self, name: &str) -> Option<Field> {
452 self.name_to_field.get(name).copied()
453 }
454
455 pub fn get_field_entry(&self, field: Field) -> Option<&FieldEntry> {
456 self.fields.get(field.0 as usize)
457 }
458
459 pub fn get_field_name(&self, field: Field) -> Option<&str> {
460 self.fields.get(field.0 as usize).map(|e| e.name.as_str())
461 }
462
463 pub fn fields(&self) -> impl Iterator<Item = (Field, &FieldEntry)> {
464 self.fields
465 .iter()
466 .enumerate()
467 .map(|(i, e)| (Field(i as u32), e))
468 }
469
470 pub fn num_fields(&self) -> usize {
471 self.fields.len()
472 }
473
474 pub fn has_reorder_fields(&self) -> bool {
477 self.fields.iter().any(|e| e.reorder)
478 }
479
480 pub fn reorder_on_merge(&self) -> bool {
483 self.reorder_on_merge
484 }
485
486 pub fn index_label(&self) -> &str {
489 if self.index_name.is_empty() {
490 "unknown"
491 } else {
492 &self.index_name
493 }
494 }
495
496 pub fn set_index_name(&mut self, name: impl Into<String>) {
498 self.index_name = name.into();
499 }
500
501 pub fn default_fields(&self) -> &[Field] {
503 &self.default_fields
504 }
505
506 pub fn set_default_fields(&mut self, fields: Vec<Field>) {
508 self.default_fields = fields;
509 }
510
511 pub fn query_routers(&self) -> &[QueryRouterRule] {
513 &self.query_routers
514 }
515
516 pub fn set_query_routers(&mut self, rules: Vec<QueryRouterRule>) {
518 self.query_routers = rules;
519 }
520
521 pub fn primary_field(&self) -> Option<Field> {
523 self.fields
524 .iter()
525 .enumerate()
526 .find(|(_, e)| e.primary_key)
527 .map(|(i, _)| Field(i as u32))
528 }
529}
530
531#[derive(Debug, Default)]
533pub struct SchemaBuilder {
534 fields: Vec<FieldEntry>,
535 default_fields: Vec<String>,
536 query_routers: Vec<QueryRouterRule>,
537 reorder_on_merge: bool,
538 index_name: String,
539}
540
541impl SchemaBuilder {
542 pub fn add_text_field(&mut self, name: &str, indexed: bool, stored: bool) -> Field {
543 self.add_field_with_tokenizer(
544 name,
545 FieldType::Text,
546 indexed,
547 stored,
548 Some("simple".to_string()),
549 )
550 }
551
552 pub fn add_text_field_with_tokenizer(
553 &mut self,
554 name: &str,
555 indexed: bool,
556 stored: bool,
557 tokenizer: &str,
558 ) -> Field {
559 self.add_field_with_tokenizer(
560 name,
561 FieldType::Text,
562 indexed,
563 stored,
564 Some(tokenizer.to_string()),
565 )
566 }
567
568 pub fn add_u64_field(&mut self, name: &str, indexed: bool, stored: bool) -> Field {
569 self.add_field(name, FieldType::U64, indexed, stored)
570 }
571
572 pub fn add_i64_field(&mut self, name: &str, indexed: bool, stored: bool) -> Field {
573 self.add_field(name, FieldType::I64, indexed, stored)
574 }
575
576 pub fn add_f64_field(&mut self, name: &str, indexed: bool, stored: bool) -> Field {
577 self.add_field(name, FieldType::F64, indexed, stored)
578 }
579
580 pub fn add_bytes_field(&mut self, name: &str, stored: bool) -> Field {
581 self.add_field(name, FieldType::Bytes, false, stored)
582 }
583
584 pub fn add_json_field(&mut self, name: &str, stored: bool) -> Field {
589 self.add_field(name, FieldType::Json, false, stored)
590 }
591
592 pub fn add_sparse_vector_field(&mut self, name: &str, indexed: bool, stored: bool) -> Field {
597 self.add_sparse_vector_field_with_config(
598 name,
599 indexed,
600 stored,
601 crate::structures::SparseVectorConfig::default(),
602 )
603 }
604
605 pub fn add_sparse_vector_field_with_config(
610 &mut self,
611 name: &str,
612 indexed: bool,
613 stored: bool,
614 config: crate::structures::SparseVectorConfig,
615 ) -> Field {
616 let field = Field(self.fields.len() as u32);
617 self.fields.push(FieldEntry {
618 name: name.to_string(),
619 field_type: FieldType::SparseVector,
620 indexed,
621 stored,
622 tokenizer: None,
623 multi: false,
624 positions: None,
625 sparse_vector_config: Some(config),
626 dense_vector_config: None,
627 binary_dense_vector_config: None,
628 fast: false,
629 primary_key: false,
630 reorder: false,
631 });
632 field
633 }
634
635 pub fn set_sparse_vector_config(
637 &mut self,
638 field: Field,
639 config: crate::structures::SparseVectorConfig,
640 ) {
641 if let Some(entry) = self.fields.get_mut(field.0 as usize) {
642 entry.sparse_vector_config = Some(config);
643 }
644 }
645
646 pub fn add_dense_vector_field(
651 &mut self,
652 name: &str,
653 dim: usize,
654 indexed: bool,
655 stored: bool,
656 ) -> Field {
657 self.add_dense_vector_field_with_config(name, indexed, stored, DenseVectorConfig::new(dim))
658 }
659
660 pub fn add_dense_vector_field_with_config(
662 &mut self,
663 name: &str,
664 indexed: bool,
665 stored: bool,
666 config: DenseVectorConfig,
667 ) -> Field {
668 let field = Field(self.fields.len() as u32);
669 self.fields.push(FieldEntry {
670 name: name.to_string(),
671 field_type: FieldType::DenseVector,
672 indexed,
673 stored,
674 tokenizer: None,
675 multi: false,
676 positions: None,
677 sparse_vector_config: None,
678 dense_vector_config: Some(config),
679 binary_dense_vector_config: None,
680 fast: false,
681 primary_key: false,
682 reorder: false,
683 });
684 field
685 }
686
687 pub fn add_binary_dense_vector_field(
693 &mut self,
694 name: &str,
695 dim: usize,
696 indexed: bool,
697 stored: bool,
698 ) -> Field {
699 self.add_binary_dense_vector_field_with_config(
700 name,
701 indexed,
702 stored,
703 BinaryDenseVectorConfig::new(dim),
704 )
705 }
706
707 pub fn add_binary_dense_vector_field_with_config(
709 &mut self,
710 name: &str,
711 indexed: bool,
712 stored: bool,
713 config: BinaryDenseVectorConfig,
714 ) -> Field {
715 let field = Field(self.fields.len() as u32);
716 self.fields.push(FieldEntry {
717 name: name.to_string(),
718 field_type: FieldType::BinaryDenseVector,
719 indexed,
720 stored,
721 tokenizer: None,
722 multi: false,
723 positions: None,
724 sparse_vector_config: None,
725 dense_vector_config: None,
726 binary_dense_vector_config: Some(config),
727 fast: false,
728 primary_key: false,
729 reorder: false,
730 });
731 field
732 }
733
734 fn add_field(
735 &mut self,
736 name: &str,
737 field_type: FieldType,
738 indexed: bool,
739 stored: bool,
740 ) -> Field {
741 self.add_field_with_tokenizer(name, field_type, indexed, stored, None)
742 }
743
744 fn add_field_with_tokenizer(
745 &mut self,
746 name: &str,
747 field_type: FieldType,
748 indexed: bool,
749 stored: bool,
750 tokenizer: Option<String>,
751 ) -> Field {
752 self.add_field_full(name, field_type, indexed, stored, tokenizer, false)
753 }
754
755 fn add_field_full(
756 &mut self,
757 name: &str,
758 field_type: FieldType,
759 indexed: bool,
760 stored: bool,
761 tokenizer: Option<String>,
762 multi: bool,
763 ) -> Field {
764 let field = Field(self.fields.len() as u32);
765 self.fields.push(FieldEntry {
766 name: name.to_string(),
767 field_type,
768 indexed,
769 stored,
770 tokenizer,
771 multi,
772 positions: None,
773 sparse_vector_config: None,
774 dense_vector_config: None,
775 binary_dense_vector_config: None,
776 fast: false,
777 primary_key: false,
778 reorder: false,
779 });
780 field
781 }
782
783 pub fn set_multi(&mut self, field: Field, multi: bool) {
785 if let Some(entry) = self.fields.get_mut(field.0 as usize) {
786 entry.multi = multi;
787 }
788 }
789
790 pub fn set_fast(&mut self, field: Field, fast: bool) {
793 if let Some(entry) = self.fields.get_mut(field.0 as usize) {
794 entry.fast = fast;
795 }
796 }
797
798 pub fn set_primary_key(&mut self, field: Field) {
804 if let Some(entry) = self.fields.get_mut(field.0 as usize) {
805 entry.primary_key = true;
806 entry.fast = true;
807 entry.indexed = true;
808 }
809 }
810
811 pub fn set_reorder(&mut self, field: Field, reorder: bool) {
813 if let Some(entry) = self.fields.get_mut(field.0 as usize) {
814 entry.reorder = reorder;
815 }
816 }
817
818 pub fn set_reorder_on_merge(&mut self, on: bool) {
821 self.reorder_on_merge = on;
822 }
823
824 pub fn set_index_name(&mut self, name: impl Into<String>) {
826 self.index_name = name.into();
827 }
828
829 pub fn set_positions(&mut self, field: Field, mode: PositionMode) {
831 if let Some(entry) = self.fields.get_mut(field.0 as usize) {
832 entry.positions = Some(mode);
833 }
834 }
835
836 pub fn set_default_fields(&mut self, field_names: Vec<String>) {
838 self.default_fields = field_names;
839 }
840
841 pub fn set_query_routers(&mut self, rules: Vec<QueryRouterRule>) {
843 self.query_routers = rules;
844 }
845
846 pub fn build(self) -> Schema {
847 let mut name_to_field = HashMap::new();
848 for (i, entry) in self.fields.iter().enumerate() {
849 name_to_field.insert(entry.name.clone(), Field(i as u32));
850 }
851
852 let default_fields: Vec<Field> = self
854 .default_fields
855 .iter()
856 .filter_map(|name| name_to_field.get(name).copied())
857 .collect();
858
859 Schema {
860 fields: self.fields,
861 name_to_field,
862 default_fields,
863 query_routers: self.query_routers,
864 reorder_on_merge: self.reorder_on_merge,
865 index_name: self.index_name,
866 }
867 }
868}
869
870#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
872pub enum FieldValue {
873 #[serde(rename = "text")]
874 Text(String),
875 #[serde(rename = "u64")]
876 U64(u64),
877 #[serde(rename = "i64")]
878 I64(i64),
879 #[serde(rename = "f64")]
880 F64(f64),
881 #[serde(rename = "bytes")]
882 Bytes(Vec<u8>),
883 #[serde(rename = "sparse_vector")]
885 SparseVector(Vec<(u32, f32)>),
886 #[serde(rename = "dense_vector")]
888 DenseVector(Vec<f32>),
889 #[serde(rename = "json")]
891 Json(serde_json::Value),
892 #[serde(rename = "binary_dense_vector")]
894 BinaryDenseVector(Vec<u8>),
895}
896
897impl FieldValue {
898 pub fn as_text(&self) -> Option<&str> {
899 match self {
900 FieldValue::Text(s) => Some(s),
901 _ => None,
902 }
903 }
904
905 pub fn as_u64(&self) -> Option<u64> {
906 match self {
907 FieldValue::U64(v) => Some(*v),
908 _ => None,
909 }
910 }
911
912 pub fn as_i64(&self) -> Option<i64> {
913 match self {
914 FieldValue::I64(v) => Some(*v),
915 _ => None,
916 }
917 }
918
919 pub fn as_f64(&self) -> Option<f64> {
920 match self {
921 FieldValue::F64(v) => Some(*v),
922 _ => None,
923 }
924 }
925
926 pub fn as_bytes(&self) -> Option<&[u8]> {
927 match self {
928 FieldValue::Bytes(b) => Some(b),
929 _ => None,
930 }
931 }
932
933 pub fn as_sparse_vector(&self) -> Option<&[(u32, f32)]> {
934 match self {
935 FieldValue::SparseVector(entries) => Some(entries),
936 _ => None,
937 }
938 }
939
940 pub fn as_dense_vector(&self) -> Option<&[f32]> {
941 match self {
942 FieldValue::DenseVector(v) => Some(v),
943 _ => None,
944 }
945 }
946
947 pub fn as_json(&self) -> Option<&serde_json::Value> {
948 match self {
949 FieldValue::Json(v) => Some(v),
950 _ => None,
951 }
952 }
953
954 pub fn as_binary_dense_vector(&self) -> Option<&[u8]> {
955 match self {
956 FieldValue::BinaryDenseVector(v) => Some(v),
957 _ => None,
958 }
959 }
960}
961
962#[derive(Debug, Clone, Default, Serialize, Deserialize)]
964pub struct Document {
965 field_values: Vec<(Field, FieldValue)>,
966}
967
968impl Document {
969 pub fn new() -> Self {
970 Self::default()
971 }
972
973 pub fn add_text(&mut self, field: Field, value: impl Into<String>) {
974 self.field_values
975 .push((field, FieldValue::Text(value.into())));
976 }
977
978 pub fn add_u64(&mut self, field: Field, value: u64) {
979 self.field_values.push((field, FieldValue::U64(value)));
980 }
981
982 pub fn add_i64(&mut self, field: Field, value: i64) {
983 self.field_values.push((field, FieldValue::I64(value)));
984 }
985
986 pub fn add_f64(&mut self, field: Field, value: f64) {
987 self.field_values.push((field, FieldValue::F64(value)));
988 }
989
990 pub fn add_bytes(&mut self, field: Field, value: Vec<u8>) {
991 self.field_values.push((field, FieldValue::Bytes(value)));
992 }
993
994 pub fn add_sparse_vector(&mut self, field: Field, entries: Vec<(u32, f32)>) {
995 self.field_values
996 .push((field, FieldValue::SparseVector(entries)));
997 }
998
999 pub fn add_dense_vector(&mut self, field: Field, values: Vec<f32>) {
1000 self.field_values
1001 .push((field, FieldValue::DenseVector(values)));
1002 }
1003
1004 pub fn add_json(&mut self, field: Field, value: serde_json::Value) {
1005 self.field_values.push((field, FieldValue::Json(value)));
1006 }
1007
1008 pub fn add_binary_dense_vector(&mut self, field: Field, values: Vec<u8>) {
1009 self.field_values
1010 .push((field, FieldValue::BinaryDenseVector(values)));
1011 }
1012
1013 pub fn get_first(&self, field: Field) -> Option<&FieldValue> {
1014 self.field_values
1015 .iter()
1016 .find(|(f, _)| *f == field)
1017 .map(|(_, v)| v)
1018 }
1019
1020 pub fn get_all(&self, field: Field) -> impl Iterator<Item = &FieldValue> {
1021 self.field_values
1022 .iter()
1023 .filter(move |(f, _)| *f == field)
1024 .map(|(_, v)| v)
1025 }
1026
1027 pub fn field_values(&self) -> &[(Field, FieldValue)] {
1028 &self.field_values
1029 }
1030
1031 pub fn filter_stored(&self, schema: &Schema) -> Document {
1033 Document {
1034 field_values: self
1035 .field_values
1036 .iter()
1037 .filter(|(field, _)| {
1038 schema
1039 .get_field_entry(*field)
1040 .is_some_and(|entry| entry.stored)
1041 })
1042 .cloned()
1043 .collect(),
1044 }
1045 }
1046
1047 pub fn to_json(&self, schema: &Schema) -> serde_json::Value {
1053 use std::collections::HashMap;
1054
1055 let mut field_values_map: HashMap<Field, (String, bool, Vec<serde_json::Value>)> =
1057 HashMap::new();
1058
1059 for (field, value) in &self.field_values {
1060 if let Some(entry) = schema.get_field_entry(*field) {
1061 let json_value = match value {
1062 FieldValue::Text(s) => serde_json::Value::String(s.clone()),
1063 FieldValue::U64(n) => serde_json::Value::Number((*n).into()),
1064 FieldValue::I64(n) => serde_json::Value::Number((*n).into()),
1065 FieldValue::F64(n) => serde_json::json!(n),
1066 FieldValue::Bytes(b) => {
1067 use base64::Engine;
1068 serde_json::Value::String(
1069 base64::engine::general_purpose::STANDARD.encode(b),
1070 )
1071 }
1072 FieldValue::SparseVector(entries) => {
1073 let indices: Vec<u32> = entries.iter().map(|(i, _)| *i).collect();
1074 let values: Vec<f32> = entries.iter().map(|(_, v)| *v).collect();
1075 serde_json::json!({
1076 "indices": indices,
1077 "values": values
1078 })
1079 }
1080 FieldValue::DenseVector(values) => {
1081 serde_json::json!(values)
1082 }
1083 FieldValue::Json(v) => v.clone(),
1084 FieldValue::BinaryDenseVector(b) => {
1085 use base64::Engine;
1086 serde_json::Value::String(
1087 base64::engine::general_purpose::STANDARD.encode(b),
1088 )
1089 }
1090 };
1091 field_values_map
1092 .entry(*field)
1093 .or_insert_with(|| (entry.name.clone(), entry.multi, Vec::new()))
1094 .2
1095 .push(json_value);
1096 }
1097 }
1098
1099 let mut map = serde_json::Map::new();
1101 for (_field, (name, is_multi, values)) in field_values_map {
1102 let json_value = if is_multi || values.len() > 1 {
1103 serde_json::Value::Array(values)
1104 } else {
1105 values.into_iter().next().unwrap()
1106 };
1107 map.insert(name, json_value);
1108 }
1109
1110 serde_json::Value::Object(map)
1111 }
1112
1113 pub fn from_json(json: &serde_json::Value, schema: &Schema) -> Option<Self> {
1122 let obj = json.as_object()?;
1123 let mut doc = Document::new();
1124
1125 for (key, value) in obj {
1126 if let Some(field) = schema.get_field(key) {
1127 let field_entry = schema.get_field_entry(field)?;
1128 Self::add_json_value(&mut doc, field, &field_entry.field_type, value);
1129 }
1130 }
1131
1132 Some(doc)
1133 }
1134
1135 fn add_json_value(
1137 doc: &mut Document,
1138 field: Field,
1139 field_type: &FieldType,
1140 value: &serde_json::Value,
1141 ) {
1142 match value {
1143 serde_json::Value::String(s) => {
1144 if matches!(field_type, FieldType::Text) {
1145 doc.add_text(field, s.clone());
1146 }
1147 }
1148 serde_json::Value::Number(n) => {
1149 match field_type {
1150 FieldType::I64 => {
1151 if let Some(i) = n.as_i64() {
1152 doc.add_i64(field, i);
1153 }
1154 }
1155 FieldType::U64 => {
1156 if let Some(u) = n.as_u64() {
1157 doc.add_u64(field, u);
1158 } else if let Some(i) = n.as_i64() {
1159 if i >= 0 {
1161 doc.add_u64(field, i as u64);
1162 }
1163 }
1164 }
1165 FieldType::F64 => {
1166 if let Some(f) = n.as_f64() {
1167 doc.add_f64(field, f);
1168 }
1169 }
1170 _ => {}
1171 }
1172 }
1173 serde_json::Value::Array(arr) => {
1175 for item in arr {
1176 Self::add_json_value(doc, field, field_type, item);
1177 }
1178 }
1179 serde_json::Value::Object(obj) if matches!(field_type, FieldType::SparseVector) => {
1181 if let (Some(indices_val), Some(values_val)) =
1182 (obj.get("indices"), obj.get("values"))
1183 {
1184 let indices: Vec<u32> = indices_val
1185 .as_array()
1186 .map(|arr| {
1187 arr.iter()
1188 .filter_map(|v| v.as_u64().map(|n| n as u32))
1189 .collect()
1190 })
1191 .unwrap_or_default();
1192 let values: Vec<f32> = values_val
1193 .as_array()
1194 .map(|arr| {
1195 arr.iter()
1196 .filter_map(|v| v.as_f64().map(|n| n as f32))
1197 .collect()
1198 })
1199 .unwrap_or_default();
1200 if indices.len() == values.len() {
1201 let entries: Vec<(u32, f32)> = indices.into_iter().zip(values).collect();
1202 doc.add_sparse_vector(field, entries);
1203 }
1204 }
1205 }
1206 _ if matches!(field_type, FieldType::Json) => {
1208 doc.add_json(field, value.clone());
1209 }
1210 serde_json::Value::Object(_) => {}
1211 _ => {}
1212 }
1213 }
1214}
1215
1216#[cfg(test)]
1217mod tests {
1218 use super::*;
1219
1220 #[test]
1221 fn test_schema_builder() {
1222 let mut builder = Schema::builder();
1223 let title = builder.add_text_field("title", true, true);
1224 let body = builder.add_text_field("body", true, false);
1225 let count = builder.add_u64_field("count", true, true);
1226 let schema = builder.build();
1227
1228 assert_eq!(schema.get_field("title"), Some(title));
1229 assert_eq!(schema.get_field("body"), Some(body));
1230 assert_eq!(schema.get_field("count"), Some(count));
1231 assert_eq!(schema.get_field("nonexistent"), None);
1232 }
1233
1234 #[test]
1235 fn test_set_primary_key_forces_fast_and_indexed() {
1236 let mut builder = Schema::builder();
1241 let id = builder.add_text_field("id", false, true);
1242 builder.set_primary_key(id);
1243 let schema = builder.build();
1244
1245 let entry = schema.get_field_entry(id).unwrap();
1246 assert!(entry.primary_key);
1247 assert!(
1248 entry.fast,
1249 "primary key must imply fast (dedup reads the fast-field text dict)"
1250 );
1251 assert!(entry.indexed, "primary key must imply indexed");
1252 }
1253
1254 #[test]
1255 fn test_document() {
1256 let mut builder = Schema::builder();
1257 let title = builder.add_text_field("title", true, true);
1258 let count = builder.add_u64_field("count", true, true);
1259 let _schema = builder.build();
1260
1261 let mut doc = Document::new();
1262 doc.add_text(title, "Hello World");
1263 doc.add_u64(count, 42);
1264
1265 assert_eq!(doc.get_first(title).unwrap().as_text(), Some("Hello World"));
1266 assert_eq!(doc.get_first(count).unwrap().as_u64(), Some(42));
1267 }
1268
1269 #[test]
1270 fn test_document_serialization() {
1271 let mut builder = Schema::builder();
1272 let title = builder.add_text_field("title", true, true);
1273 let count = builder.add_u64_field("count", true, true);
1274 let _schema = builder.build();
1275
1276 let mut doc = Document::new();
1277 doc.add_text(title, "Hello World");
1278 doc.add_u64(count, 42);
1279
1280 let json = serde_json::to_string(&doc).unwrap();
1282 println!("Serialized doc: {}", json);
1283
1284 let doc2: Document = serde_json::from_str(&json).unwrap();
1286 assert_eq!(
1287 doc2.field_values().len(),
1288 2,
1289 "Should have 2 field values after deserialization"
1290 );
1291 assert_eq!(
1292 doc2.get_first(title).unwrap().as_text(),
1293 Some("Hello World")
1294 );
1295 assert_eq!(doc2.get_first(count).unwrap().as_u64(), Some(42));
1296 }
1297
1298 #[test]
1299 fn test_multivalue_field() {
1300 let mut builder = Schema::builder();
1301 let uris = builder.add_text_field("uris", true, true);
1302 let title = builder.add_text_field("title", true, true);
1303 let schema = builder.build();
1304
1305 let mut doc = Document::new();
1307 doc.add_text(uris, "one");
1308 doc.add_text(uris, "two");
1309 doc.add_text(title, "Test Document");
1310
1311 assert_eq!(doc.get_first(uris).unwrap().as_text(), Some("one"));
1313
1314 let all_uris: Vec<_> = doc.get_all(uris).collect();
1316 assert_eq!(all_uris.len(), 2);
1317 assert_eq!(all_uris[0].as_text(), Some("one"));
1318 assert_eq!(all_uris[1].as_text(), Some("two"));
1319
1320 let json = doc.to_json(&schema);
1322 let uris_json = json.get("uris").unwrap();
1323 assert!(uris_json.is_array(), "Multi-value field should be an array");
1324 let uris_arr = uris_json.as_array().unwrap();
1325 assert_eq!(uris_arr.len(), 2);
1326 assert_eq!(uris_arr[0].as_str(), Some("one"));
1327 assert_eq!(uris_arr[1].as_str(), Some("two"));
1328
1329 let title_json = json.get("title").unwrap();
1331 assert!(
1332 title_json.is_string(),
1333 "Single-value field should be a string"
1334 );
1335 assert_eq!(title_json.as_str(), Some("Test Document"));
1336 }
1337
1338 #[test]
1339 fn test_multivalue_from_json() {
1340 let mut builder = Schema::builder();
1341 let uris = builder.add_text_field("uris", true, true);
1342 let title = builder.add_text_field("title", true, true);
1343 let schema = builder.build();
1344
1345 let json = serde_json::json!({
1347 "uris": ["one", "two"],
1348 "title": "Test Document"
1349 });
1350
1351 let doc = Document::from_json(&json, &schema).unwrap();
1353
1354 let all_uris: Vec<_> = doc.get_all(uris).collect();
1356 assert_eq!(all_uris.len(), 2);
1357 assert_eq!(all_uris[0].as_text(), Some("one"));
1358 assert_eq!(all_uris[1].as_text(), Some("two"));
1359
1360 assert_eq!(
1362 doc.get_first(title).unwrap().as_text(),
1363 Some("Test Document")
1364 );
1365
1366 let json_out = doc.to_json(&schema);
1368 let uris_out = json_out.get("uris").unwrap().as_array().unwrap();
1369 assert_eq!(uris_out.len(), 2);
1370 assert_eq!(uris_out[0].as_str(), Some("one"));
1371 assert_eq!(uris_out[1].as_str(), Some("two"));
1372 }
1373
1374 #[test]
1375 fn test_multi_attribute_forces_array() {
1376 let mut builder = Schema::builder();
1379 let uris = builder.add_text_field("uris", true, true);
1380 builder.set_multi(uris, true); let title = builder.add_text_field("title", true, true);
1382 let schema = builder.build();
1383
1384 assert!(schema.get_field_entry(uris).unwrap().multi);
1386 assert!(!schema.get_field_entry(title).unwrap().multi);
1387
1388 let mut doc = Document::new();
1390 doc.add_text(uris, "only_one");
1391 doc.add_text(title, "Test Document");
1392
1393 let json = doc.to_json(&schema);
1395
1396 let uris_json = json.get("uris").unwrap();
1397 assert!(
1398 uris_json.is_array(),
1399 "Multi field should be array even with single value"
1400 );
1401 let uris_arr = uris_json.as_array().unwrap();
1402 assert_eq!(uris_arr.len(), 1);
1403 assert_eq!(uris_arr[0].as_str(), Some("only_one"));
1404
1405 let title_json = json.get("title").unwrap();
1407 assert!(
1408 title_json.is_string(),
1409 "Non-multi single-value field should be a string"
1410 );
1411 assert_eq!(title_json.as_str(), Some("Test Document"));
1412 }
1413
1414 #[test]
1415 fn test_sparse_vector_field() {
1416 let mut builder = Schema::builder();
1417 let embedding = builder.add_sparse_vector_field("embedding", true, true);
1418 let title = builder.add_text_field("title", true, true);
1419 let schema = builder.build();
1420
1421 assert_eq!(schema.get_field("embedding"), Some(embedding));
1422 assert_eq!(
1423 schema.get_field_entry(embedding).unwrap().field_type,
1424 FieldType::SparseVector
1425 );
1426
1427 let mut doc = Document::new();
1429 doc.add_sparse_vector(embedding, vec![(0, 1.0), (5, 2.5), (10, 0.5)]);
1430 doc.add_text(title, "Test Document");
1431
1432 let entries = doc
1434 .get_first(embedding)
1435 .unwrap()
1436 .as_sparse_vector()
1437 .unwrap();
1438 assert_eq!(entries, &[(0, 1.0), (5, 2.5), (10, 0.5)]);
1439
1440 let json = doc.to_json(&schema);
1442 let embedding_json = json.get("embedding").unwrap();
1443 assert!(embedding_json.is_object());
1444 assert_eq!(
1445 embedding_json
1446 .get("indices")
1447 .unwrap()
1448 .as_array()
1449 .unwrap()
1450 .len(),
1451 3
1452 );
1453
1454 let doc2 = Document::from_json(&json, &schema).unwrap();
1456 let entries2 = doc2
1457 .get_first(embedding)
1458 .unwrap()
1459 .as_sparse_vector()
1460 .unwrap();
1461 assert_eq!(entries2[0].0, 0);
1462 assert!((entries2[0].1 - 1.0).abs() < 1e-6);
1463 assert_eq!(entries2[1].0, 5);
1464 assert!((entries2[1].1 - 2.5).abs() < 1e-6);
1465 assert_eq!(entries2[2].0, 10);
1466 assert!((entries2[2].1 - 0.5).abs() < 1e-6);
1467 }
1468
1469 #[test]
1470 fn test_json_field() {
1471 let mut builder = Schema::builder();
1472 let metadata = builder.add_json_field("metadata", true);
1473 let title = builder.add_text_field("title", true, true);
1474 let schema = builder.build();
1475
1476 assert_eq!(schema.get_field("metadata"), Some(metadata));
1477 assert_eq!(
1478 schema.get_field_entry(metadata).unwrap().field_type,
1479 FieldType::Json
1480 );
1481 assert!(!schema.get_field_entry(metadata).unwrap().indexed);
1483 assert!(schema.get_field_entry(metadata).unwrap().stored);
1484
1485 let json_value = serde_json::json!({
1487 "author": "John Doe",
1488 "tags": ["rust", "search"],
1489 "nested": {"key": "value"}
1490 });
1491 let mut doc = Document::new();
1492 doc.add_json(metadata, json_value.clone());
1493 doc.add_text(title, "Test Document");
1494
1495 let stored_json = doc.get_first(metadata).unwrap().as_json().unwrap();
1497 assert_eq!(stored_json, &json_value);
1498 assert_eq!(
1499 stored_json.get("author").unwrap().as_str(),
1500 Some("John Doe")
1501 );
1502
1503 let doc_json = doc.to_json(&schema);
1505 let metadata_out = doc_json.get("metadata").unwrap();
1506 assert_eq!(metadata_out, &json_value);
1507
1508 let doc2 = Document::from_json(&doc_json, &schema).unwrap();
1510 let stored_json2 = doc2.get_first(metadata).unwrap().as_json().unwrap();
1511 assert_eq!(stored_json2, &json_value);
1512 }
1513
1514 #[test]
1515 fn test_json_field_various_types() {
1516 let mut builder = Schema::builder();
1517 let data = builder.add_json_field("data", true);
1518 let _schema = builder.build();
1519
1520 let arr_value = serde_json::json!([1, 2, 3, "four", null]);
1522 let mut doc = Document::new();
1523 doc.add_json(data, arr_value.clone());
1524 assert_eq!(doc.get_first(data).unwrap().as_json().unwrap(), &arr_value);
1525
1526 let str_value = serde_json::json!("just a string");
1528 let mut doc2 = Document::new();
1529 doc2.add_json(data, str_value.clone());
1530 assert_eq!(doc2.get_first(data).unwrap().as_json().unwrap(), &str_value);
1531
1532 let num_value = serde_json::json!(42.5);
1534 let mut doc3 = Document::new();
1535 doc3.add_json(data, num_value.clone());
1536 assert_eq!(doc3.get_first(data).unwrap().as_json().unwrap(), &num_value);
1537
1538 let null_value = serde_json::Value::Null;
1540 let mut doc4 = Document::new();
1541 doc4.add_json(data, null_value.clone());
1542 assert_eq!(
1543 doc4.get_first(data).unwrap().as_json().unwrap(),
1544 &null_value
1545 );
1546
1547 let bool_value = serde_json::json!(true);
1549 let mut doc5 = Document::new();
1550 doc5.add_json(data, bool_value.clone());
1551 assert_eq!(
1552 doc5.get_first(data).unwrap().as_json().unwrap(),
1553 &bool_value
1554 );
1555 }
1556}