1use add_result::decode_positions_commit;
2use ahash::{AHashMap, AHashSet};
3use futures::future;
4use indexmap::IndexMap;
5use itertools::Itertools;
6use memmap2::{Mmap, MmapMut, MmapOptions};
7use model2vec_rs::model::StaticModel;
8use num::FromPrimitive;
9use num_derive::FromPrimitive;
10
11use search::{QueryType, Search};
12use serde::{Deserialize, Serialize};
13use serde_json::Value;
14use smallvec::SmallVec;
15use snowball_stemmers_rs::{Algorithm, Stemmer};
16use std::{
17 cmp,
18 collections::HashMap,
19 fmt::{self},
20 fs::{self, File},
21 io::{BufRead, BufReader, Read, Seek, Write},
22 path::Path,
23 sync::{Arc, LazyLock},
24 thread::available_parallelism,
25 time::Instant,
26};
27use symspell_complete_rs::{PruningRadixTrie, SymSpell};
28use tokio::sync::{RwLock, Semaphore};
29use utils::{read_u32, write_u16};
30use utoipa::ToSchema;
31
32#[cfg(feature = "zh")]
33use crate::word_segmentation::WordSegmentationTM;
34use crate::{
35 INDEX_RUNTIME,
36 add_result::{self, B, K, SIGMA},
37 clustering::{ClusterHeader, ParentMedoid},
38 commit::Commit,
39 geo_search::encode_morton_2_d,
40 highlighter::Highlight,
41 search::{
42 self, FacetFilter, Point, QueryFacet, QueryRewriting, Ranges, ResultObject, ResultSort,
43 ResultType, SearchLexicalShard, SearchMode,
44 },
45 tokenizer::tokenizer,
46 utils::{
47 self, read_u8_ref, read_u16, read_u16_ref, read_u32_ref, read_u64, read_u64_ref, write_f32,
48 write_f64, write_i8, write_i16, write_i32, write_i64, write_u32, write_u64,
49 },
50 vector::{Inference, Model, Precision, Quantization, VectorHeader, read_min_max},
51 vector_similarity::{TurboQuant, VectorSimilarity},
52};
53
54#[cfg(any(
55 all(
56 feature = "gxhash",
57 target_arch = "x86_64",
58 target_feature = "aes",
59 target_feature = "sse2"
60 ),
61 all(
62 feature = "gxhash",
63 target_arch = "aarch64",
64 target_feature = "aes",
65 target_feature = "neon"
66 )
67))]
68use gxhash::{gxhash32, gxhash64};
69
70#[cfg(not(any(
71 all(
72 feature = "gxhash",
73 target_arch = "x86_64",
74 target_feature = "aes",
75 target_feature = "sse2"
76 ),
77 all(
78 feature = "gxhash",
79 target_arch = "aarch64",
80 target_feature = "aes",
81 target_feature = "neon"
82 )
83)))]
84use ahash::RandomState;
85
86pub(crate) const FILE_PATH: &str = "files";
87pub(crate) const INDEX_FILENAME: &str = "index.bin";
88pub(crate) const DOCSTORE_FILENAME: &str = "docstore.bin";
89pub(crate) const DELETE_FILENAME: &str = "delete.bin";
90pub(crate) const SCHEMA_FILENAME: &str = "schema.json";
91pub(crate) const SYNONYMS_FILENAME: &str = "synonyms.json";
92pub(crate) const META_FILENAME: &str = "index.json";
93pub(crate) const FACET_FILENAME: &str = "facet.bin";
94pub(crate) const FACET_VALUES_FILENAME: &str = "facet.json";
95
96pub(crate) const DICTIONARY_FILENAME: &str = "dictionary.csv";
97pub(crate) const COMPLETIONS_FILENAME: &str = "completions.csv";
98
99pub(crate) const VERSION: &str = env!("CARGO_PKG_VERSION");
100
101pub(crate) const VECTOR_FILENAME: &str = "vector.bin";
102
103const INDEX_HEADER_SIZE: u64 = 4;
104pub const INDEX_FORMAT_VERSION_MAJOR: u16 = 6;
106pub const INDEX_FORMAT_VERSION_MINOR: u16 = 1;
108
109pub const MAX_POSITIONS_PER_TERM: usize = 65_536;
111pub(crate) const STOP_BIT: u8 = 0b10000000;
112pub(crate) const FIELD_STOP_BIT_1: u8 = 0b0010_0000;
113pub(crate) const FIELD_STOP_BIT_2: u8 = 0b0100_0000;
114pub const ROARING_BLOCK_SIZE: usize = 65_536;
116
117pub(crate) const SPEEDUP_FLAG: bool = true;
118pub(crate) const SORT_FLAG: bool = true;
119
120pub(crate) const POSTING_BUFFER_SIZE: usize = 400_000_000;
121pub(crate) const MAX_QUERY_TERM_NUMBER: usize = 100;
122pub(crate) const SEGMENT_KEY_CAPACITY: usize = 1000;
123
124use tabled::Tabled;
125
126#[derive(Tabled, Clone)]
128pub struct Info {
129 pub entry: &'static str,
131 pub value: String,
133}
134
135#[derive(Deserialize, Serialize, Clone, ToSchema, Debug)]
137pub struct SearchRequestObject {
138 #[serde(rename = "query")]
140 pub query_string: String,
141 #[serde(default)]
143 pub query_vector: Option<Value>,
144 #[serde(default)]
145 #[schema(required = false, default = false, example = false)]
146 pub enable_empty_query: bool,
150 #[serde(default)]
151 #[schema(required = false, minimum = 0, default = 0, example = 0)]
152 pub offset: usize,
154 #[serde(default = "length_api")]
156 #[schema(required = false, minimum = 1, default = 10, example = 10)]
157 pub length: usize,
158 #[serde(default)]
159 pub result_type: ResultType,
161 #[serde(default)]
163 pub realtime: bool,
164 #[serde(default)]
166 pub highlights: Vec<Highlight>,
167 #[schema(required = false, example = json!(["title"]))]
169 #[serde(default)]
170 pub field_filter: Vec<String>,
171 #[serde(default)]
173 pub fields: Vec<String>,
174 #[serde(default)]
176 pub distance_fields: Vec<DistanceField>,
177 #[serde(default)]
179 pub query_facets: Vec<QueryFacet>,
180 #[serde(default)]
182 pub facet_filter: Vec<FacetFilter>,
183 #[schema(required = false, example = json!([{"field": "date", "order": "Ascending", "base": "None" }]))]
195 #[serde(default)]
196 pub result_sort: Vec<ResultSort>,
197 #[schema(required = false, example = QueryType::Intersection)]
199 #[serde(default = "query_type_api")]
200 pub query_type_default: QueryType,
201 #[schema(required = false, example = QueryRewriting::SearchOnly)]
203 #[serde(default = "query_rewriting_api")]
204 pub query_rewriting: QueryRewriting,
205 #[schema(required = false, example = SearchMode::Lexical)]
207 #[serde(default = "search_mode_api")]
208 pub search_mode: SearchMode,
209}
210
211fn search_mode_api() -> SearchMode {
212 SearchMode::Lexical
213}
214
215fn query_type_api() -> QueryType {
216 QueryType::Intersection
217}
218
219fn query_rewriting_api() -> QueryRewriting {
220 QueryRewriting::SearchOnly
221}
222
223fn length_api() -> usize {
224 10
225}
226
227#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)]
228pub struct SearchResultObject {
230 pub time: u128,
232 pub original_query: String,
234 pub query: String,
236 pub offset: usize,
238 pub length: usize,
240 pub count: usize,
242 pub count_total: usize,
244 pub query_terms: Vec<String>,
246 #[schema(value_type=Vec<HashMap<String, serde_json::Value>>)]
247 pub results: Vec<Document>,
249 #[schema(value_type=HashMap<String, Vec<(String, usize)>>)]
250 pub facets: AHashMap<String, Facet>,
252 pub suggestions: Vec<String>,
254}
255
256#[derive(Default, Debug, Clone, Deserialize, Serialize, ToSchema)]
258pub struct ApikeyQuotaObject {
259 pub indices_max: usize,
261 pub indices_size_max: usize,
263 pub documents_max: usize,
265 pub operations_max: usize,
267 pub rate_limit: Option<usize>,
269 #[serde(skip)]
271 #[schema(ignore)]
272 pub timestamp_nanos: usize,
273 #[serde(skip)]
274 #[schema(ignore)]
275 pub violation_count: usize,
277 #[serde(default)]
279 pub demo: bool,
280}
281
282#[derive(Deserialize, Serialize)]
283pub struct ApikeyObject {
285 pub id: u64,
287 pub apikey_hash: u128,
289 pub quota: ApikeyQuotaObject,
291
292 #[serde(skip)]
294 pub index_list: HashMap<u64, IndexArc>,
295}
296
297#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)]
299pub struct CreateIndexRequest {
300 #[schema(example = "demo_index")]
302 pub index_name: String,
303 #[schema(required = true, example = json!([
304 {"field":"title","field_type":"Text","store":true,"index_lexical":true,"boost":10.0},
305 {"field":"body","field_type":"Text","store":true,"index_lexical":true,"longest":true},
306 {"field":"url","field_type":"Text","store":true,"index_lexical":false},
307 {"field":"date","field_type":"Timestamp","store":true,"index_lexical":false,"facet":true}]))]
308 #[serde(default)]
310 pub schema: Vec<SchemaField>,
311 #[serde(default = "similarity_type_api")]
313 pub similarity: LexicalSimilarity,
314 #[serde(default = "tokenizer_type_api")]
316 pub tokenizer: TokenizerType,
317 #[serde(default)]
318 pub stemmer: StemmerType,
320 #[serde(default)]
322 pub stop_words: StopwordType,
323 #[serde(default)]
325 pub frequent_words: FrequentwordType,
326 #[serde(default = "ngram_indexing_api")]
340 pub ngram_indexing: u8,
341 #[serde(default = "document_compression_api")]
343 pub document_compression: DocumentCompression,
344 #[schema(required = false, example = json!([{"terms":["berry","lingonberry","blueberry","gooseberry"],"multiway":false}]))]
346 #[serde(default)]
347 pub synonyms: Vec<Synonym>,
348 #[serde(default)]
358 pub spelling_correction: Option<SpellingCorrection>,
359 #[serde(default)]
361 pub query_completion: Option<QueryCompletion>,
362 #[serde(default)]
363 pub clustering: Clustering,
365 #[serde(default)]
367 pub inference: Inference,
368}
369
370fn similarity_type_api() -> LexicalSimilarity {
371 LexicalSimilarity::Bm25fProximity
372}
373
374fn tokenizer_type_api() -> TokenizerType {
375 TokenizerType::UnicodeAlphanumeric
376}
377
378fn ngram_indexing_api() -> u8 {
379 NgramSet::NgramFF as u8 | NgramSet::NgramFFF as u8
380}
381
382fn document_compression_api() -> DocumentCompression {
383 DocumentCompression::Snappy
384}
385
386#[derive(Debug, Clone, Deserialize, Serialize)]
387pub struct DeleteApikeyRequest {
389 pub apikey_base64: String,
391}
392
393#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)]
395pub struct GetIteratorRequest {
396 #[serde(default)]
400 pub document_id: Option<u64>,
401 #[serde(default)]
403 pub skip: usize,
404 #[serde(default = "default_1usize")]
407 pub take: isize,
408 #[serde(default)]
410 pub include_deleted: bool,
411 #[serde(default)]
413 pub include_document: bool,
414 #[serde(default)]
416 pub fields: Vec<String>,
417}
418
419fn default_1usize() -> isize {
420 1
421}
422
423#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)]
425pub struct GetDocumentRequest {
426 #[serde(default)]
428 pub query_terms: Vec<String>,
429 #[serde(default)]
431 pub highlights: Vec<Highlight>,
432 #[serde(default)]
434 pub fields: Vec<String>,
435 #[serde(default)]
437 pub distance_fields: Vec<DistanceField>,
438}
439
440#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)]
441pub struct IndexResponseObject {
443 pub id: u64,
445 #[schema(example = "demo_index")]
447 pub name: String,
448 #[schema(example = json!({
449 "title":{
450 "field":"title",
451 "store":true,
452 "index_lexical":true,
453 "field_type":"Text",
454 "boost":10.0,
455 "field_id":0
456 },
457 "body":{
458 "field":"body",
459 "store":true,
460 "index_lexical":true,
461 "field_type":"Text",
462 "field_id":1
463 },
464 "url":{
465 "field":"url",
466 "store":true,
467 "index_lexical":false,
468 "field_type":"Text",
469 "field_id":2
470 },
471 "date":{
472 "field":"date",
473 "store":true,
474 "index_lexical":false,
475 "field_type":"Timestamp",
476 "facet":true,
477 "field_id":3
478 }
479 }))]
480 pub schema: HashMap<String, SchemaField>,
482 pub indexed_doc_count: usize,
484 pub committed_doc_count: usize,
486 pub operations_count: u64,
488 pub query_count: u64,
490 #[schema(example = "0.11.1")]
492 pub version: String,
493 #[schema(example = json!({"date":{"min":831306011,"max":1730901447}}))]
495 pub facets_minmax: HashMap<String, MinMaxFieldJson>,
496}
497
498pub type Document = IndexMap<String, Value>;
500
501#[derive(Clone, PartialEq)]
503pub enum FileType {
504 Path(Box<Path>),
506 Bytes(Box<Path>, Box<[u8]>),
508 None,
510}
511
512#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, ToSchema)]
514pub enum DocumentCompression {
515 None,
517 Lz4,
519 Snappy,
521 Zstd,
523}
524
525impl fmt::Display for DocumentCompression {
526 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
527 match self {
528 DocumentCompression::None => write!(f, "None"),
529 DocumentCompression::Lz4 => write!(f, "Lz4"),
530 DocumentCompression::Snappy => write!(f, "Snappy"),
531 DocumentCompression::Zstd => write!(f, "Zstd"),
532 }
533 }
534}
535
536#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
542pub enum AccessType {
543 Ram = 0,
549 Mmap = 1,
555}
556
557#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default, ToSchema)]
561pub enum LexicalSimilarity {
562 Bm25f = 0,
564 #[default]
566 Bm25fProximity = 1,
567}
568
569impl fmt::Display for LexicalSimilarity {
570 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
571 match self {
572 LexicalSimilarity::Bm25f => write!(f, "Bm25f"),
573 LexicalSimilarity::Bm25fProximity => write!(f, "Bm25fProximity"),
574 }
575 }
576}
577
578#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Copy, Default, ToSchema)]
600pub enum TokenizerType {
601 #[default]
603 AsciiAlphabetic = 0,
604 UnicodeAlphanumeric = 1,
607 UnicodeAlphanumericFolded = 2,
613 Whitespace = 3,
615 WhitespaceLowercase = 4,
617 #[cfg(feature = "zh")]
622 UnicodeAlphanumericZH = 5,
623}
624
625impl fmt::Display for TokenizerType {
626 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
627 match self {
628 TokenizerType::AsciiAlphabetic => write!(f, "AsciiAlphabetic"),
629 TokenizerType::UnicodeAlphanumeric => write!(f, "UnicodeAlphanumeric"),
630 TokenizerType::UnicodeAlphanumericFolded => write!(f, "UnicodeAlphanumericFolded"),
631 TokenizerType::Whitespace => write!(f, "Whitespace"),
632 TokenizerType::WhitespaceLowercase => write!(f, "WhitespaceLowercase"),
633 #[cfg(feature = "zh")]
634 TokenizerType::UnicodeAlphanumericZH => write!(f, "UnicodeAlphanumericZH"),
635 }
636 }
637}
638
639#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Copy, Default, ToSchema)]
642pub enum StemmerType {
643 #[default]
645 None = 0,
646 Arabic = 1,
648 Armenian = 2,
650 Basque = 3,
652 Catalan = 4,
654 Czech = 5,
656 Danish = 6,
658 Dutch = 7,
660 DutchPorter = 8,
662 English = 9,
664 Esperanto = 10,
666 Estonian = 11,
668 Finnish = 12,
670 French = 13,
672 German = 14,
674 Greek = 15,
676 Hindi = 16,
678 Hungarian = 17,
680 Indonesian = 18,
682 Irish = 19,
684 Italian = 20,
686 Lithuanian = 21,
688 Lovins = 22,
690 Nepali = 23,
692 Norwegian = 24,
694 Persian = 25,
696 Polish = 26,
698 Porter = 27,
700 Portuguese = 28,
702 Romanian = 29,
704 Russian = 30,
706 Serbian = 31,
708 Sesotho = 32,
710 Spanish = 33,
712 Swedish = 34,
714 Tamil = 35,
716 Turkish = 36,
718 Ukrainian = 37,
720 Yiddish = 38,
722}
723
724impl fmt::Display for StemmerType {
725 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
726 match self {
727 StemmerType::None => write!(f, "None"),
728 StemmerType::Arabic => write!(f, "Arabic"),
729 StemmerType::Armenian => write!(f, "Armenian"),
730 StemmerType::Basque => write!(f, "Basque"),
731 StemmerType::Catalan => write!(f, "Catalan"),
732 StemmerType::Czech => write!(f, "Czech"),
733 StemmerType::Danish => write!(f, "Danish"),
734 StemmerType::Dutch => write!(f, "Dutch"),
735 StemmerType::DutchPorter => write!(f, "DutchPorter"),
736 StemmerType::English => write!(f, "English"),
737 StemmerType::Esperanto => write!(f, "Esperanto"),
738 StemmerType::Estonian => write!(f, "Estonian"),
739 StemmerType::Finnish => write!(f, "Finnish"),
740 StemmerType::French => write!(f, "French"),
741 StemmerType::German => write!(f, "German"),
742 StemmerType::Greek => write!(f, "Greek"),
743 StemmerType::Hindi => write!(f, "Hindi"),
744 StemmerType::Hungarian => write!(f, "Hungarian"),
745 StemmerType::Indonesian => write!(f, "Indonesian"),
746 StemmerType::Irish => write!(f, "Irish"),
747 StemmerType::Italian => write!(f, "Italian"),
748 StemmerType::Lithuanian => write!(f, "Lithuanian"),
749 StemmerType::Lovins => write!(f, "Lovins"),
750 StemmerType::Nepali => write!(f, "Nepali"),
751 StemmerType::Norwegian => write!(f, "Norwegian"),
752 StemmerType::Persian => write!(f, "Persian"),
753 StemmerType::Polish => write!(f, "Polish"),
754 StemmerType::Porter => write!(f, "Porter"),
755 StemmerType::Portuguese => write!(f, "Portuguese"),
756 StemmerType::Romanian => write!(f, "Romanian"),
757 StemmerType::Russian => write!(f, "Russian"),
758 StemmerType::Serbian => write!(f, "Serbian"),
759 StemmerType::Sesotho => write!(f, "Sesotho"),
760 StemmerType::Spanish => write!(f, "Spanish"),
761 StemmerType::Swedish => write!(f, "Swedish"),
762 StemmerType::Tamil => write!(f, "Tamil"),
763 StemmerType::Turkish => write!(f, "Turkish"),
764 StemmerType::Ukrainian => write!(f, "Ukrainian"),
765 StemmerType::Yiddish => write!(f, "Yiddish"),
766 }
767 }
768}
769
770pub(crate) struct LevelIndex {
771 pub document_length_compressed_array: Vec<[u8; ROARING_BLOCK_SIZE]>,
772
773 pub docstore_pointer_docs: Vec<u8>,
774 pub docstore_pointer_docs_pointer: usize,
775 pub document_length_compressed_array_pointer: usize,
776}
777
778#[derive(Default, Debug, Deserialize, Serialize, Clone)]
781pub(crate) struct BlockObjectIndex {
782 pub max_block_score: f32,
783 pub block_id: u32,
784 pub compression_type_pointer: u32,
785 pub posting_count: u16,
786 pub max_docid: u16,
787 pub max_p_docid: u16,
788 pub pointer_pivot_p_docid: u16,
789}
790
791#[derive(Default)]
793pub(crate) struct PostingListObjectIndex {
794 pub posting_count: u32,
795 pub posting_count_ngram_1: u32,
796 pub posting_count_ngram_2: u32,
797 pub posting_count_ngram_3: u32,
798 pub posting_count_ngram_1_compressed: u8,
799 pub posting_count_ngram_2_compressed: u8,
800 pub posting_count_ngram_3_compressed: u8,
801 pub max_list_score: f32,
802 pub blocks: Vec<BlockObjectIndex>,
803
804 pub position_range_previous: u32,
805}
806
807#[derive(Default, Debug, Deserialize, Serialize, Clone)]
808pub(crate) struct PostingListObject0 {
809 pub pointer_first: usize,
810 pub pointer_last: usize,
811 pub posting_count: usize,
812
813 pub max_block_score: f32,
814 pub max_docid: u16,
815 pub max_p_docid: u16,
816
817 pub ngram_type: NgramType,
818 pub term_ngram1: String,
819 pub term_ngram2: String,
820 pub term_ngram3: String,
821 pub posting_count_ngram_1: f32,
822 pub posting_count_ngram_2: f32,
823 pub posting_count_ngram_3: f32,
824 pub posting_count_ngram_1_compressed: u8,
825 pub posting_count_ngram_2_compressed: u8,
826 pub posting_count_ngram_3_compressed: u8,
827
828 pub position_count: usize,
829 pub pointer_pivot_p_docid: u16,
830 pub size_compressed_positions_key: usize,
831 pub docid_delta_max: u16,
832 pub docid_old: u16,
833 pub compression_type_pointer: u32,
834}
835
836#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, FromPrimitive)]
838pub(crate) enum CompressionType {
839 Delta = 0,
840 Array = 1,
841 Bitmap = 2,
842 Rle = 3,
843}
844
845pub(crate) struct QueueObject<'a> {
846 pub query_list: Vec<PostingListObjectQuery<'a>>,
847 pub query_index: usize,
848 pub max_score: f32,
849}
850
851#[derive(Clone)]
853pub(crate) struct PostingListObjectQuery<'a> {
854 pub posting_count: u32,
855 pub max_list_score: f32,
856 pub blocks: &'a Vec<BlockObjectIndex>,
857 pub blocks_index: usize,
858
859 pub term: String,
860 pub key0: u32,
861
862 pub compression_type: CompressionType,
863 pub rank_position_pointer_range: u32,
864 pub compressed_doc_id_range: usize,
865 pub pointer_pivot_p_docid: u16,
866
867 pub posting_pointer: usize,
868 pub posting_pointer_previous: usize,
869
870 pub byte_array: &'a [u8],
871
872 pub p_block: i32,
873 pub p_block_max: i32,
874 pub p_docid: usize,
875 pub p_docid_count: usize,
876
877 pub rangebits: i32,
878 pub docid: i32,
879 pub bitposition: u32,
880
881 pub intersect: u64,
882 pub ulong_pos: usize,
883
884 pub run_end: i32,
885 pub p_run: i32,
886 pub p_run_count: i32,
887 pub p_run_sum: i32,
888
889 pub term_index_unique: usize,
890 pub positions_count: u32,
891 pub positions_pointer: u32,
892
893 pub idf: f32,
894 pub idf_ngram1: f32,
895 pub idf_ngram2: f32,
896 pub idf_ngram3: f32,
897 pub tf_ngram1: u32,
898 pub tf_ngram2: u32,
899 pub tf_ngram3: u32,
900 pub ngram_type: NgramType,
901
902 pub end_flag: bool,
903 pub end_flag_block: bool,
904 pub is_embedded: bool,
905 pub embedded_positions: [u32; 4],
906 pub field_vec: SmallVec<[(u16, usize); 2]>,
907 pub field_vec_ngram1: SmallVec<[(u16, usize); 2]>,
908 pub field_vec_ngram2: SmallVec<[(u16, usize); 2]>,
909 pub field_vec_ngram3: SmallVec<[(u16, usize); 2]>,
910 pub bm25_flag: bool,
911}
912
913pub(crate) static DUMMY_VEC: Vec<BlockObjectIndex> = Vec::new();
914pub(crate) static DUMMY_VEC_8: Vec<u8> = Vec::new();
915
916impl Default for PostingListObjectQuery<'_> {
917 fn default() -> Self {
918 Self {
919 posting_count: 0,
920 max_list_score: 0.0,
921 blocks: &DUMMY_VEC,
922 blocks_index: 0,
923 term: "".to_string(),
924 key0: 0,
925 compression_type: CompressionType::Delta,
926 rank_position_pointer_range: 0,
927 compressed_doc_id_range: 0,
928 pointer_pivot_p_docid: 0,
929 posting_pointer: 0,
930 posting_pointer_previous: 0,
931 byte_array: &DUMMY_VEC_8,
932 p_block: 0,
933 p_block_max: 0,
934 p_docid: 0,
935 p_docid_count: 0,
936 rangebits: 0,
937 docid: 0,
938 bitposition: 0,
939 run_end: 0,
940 p_run: 0,
941 p_run_count: 0,
942 p_run_sum: 0,
943 term_index_unique: 0,
944 positions_count: 0,
945 positions_pointer: 0,
946 idf: 0.0,
947 idf_ngram1: 0.0,
948 idf_ngram2: 0.0,
949 idf_ngram3: 0.0,
950 ngram_type: NgramType::SingleTerm,
951 is_embedded: false,
952 embedded_positions: [0; 4],
953 field_vec: SmallVec::new(),
954 tf_ngram1: 0,
955 tf_ngram2: 0,
956 tf_ngram3: 0,
957 field_vec_ngram1: SmallVec::new(),
958 field_vec_ngram2: SmallVec::new(),
959 field_vec_ngram3: SmallVec::new(),
960
961 end_flag: false,
962 end_flag_block: false,
963 bm25_flag: true,
964 intersect: 0,
965 ulong_pos: 0,
966 }
967 }
968}
969
970#[derive(Clone)]
973pub(crate) struct NonUniquePostingListObjectQuery<'a> {
974 pub term_index_unique: usize,
975 pub term_index_nonunique: usize,
976 pub pos: u32,
977 pub p_pos: i32,
978 pub positions_pointer: usize,
979 pub positions_count: u32,
980 pub byte_array: &'a [u8],
981 pub key0: u32,
982 pub is_embedded: bool,
983 pub embedded_positions: [u32; 4],
984 pub p_field: usize,
985 pub field_vec: SmallVec<[(u16, usize); 2]>,
986}
987
988pub(crate) struct SegmentIndex {
992 pub byte_array_blocks: Vec<Vec<u8>>,
993 pub byte_array_blocks_pointer: Vec<(usize, usize, u32)>,
994 pub segment: AHashMap<u64, PostingListObjectIndex>,
995}
996
997#[derive(Default, Debug, Clone)]
1000pub(crate) struct SegmentLevel0 {
1001 pub segment: AHashMap<u64, PostingListObject0>,
1002 pub positions_compressed: Vec<u8>,
1003}
1004
1005#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default, ToSchema)]
1007pub enum FieldType {
1008 U8,
1010 U16,
1012 U32,
1014 U64,
1016 I8,
1018 I16,
1020 I32,
1022 I64,
1024 Timestamp,
1028 F32,
1030 F64,
1032 Bool,
1034 String16,
1038 String32,
1042 StringSet16,
1046 StringSet32,
1050 Point,
1057 #[default]
1059 Text,
1060 Json,
1066 Binary,
1075}
1076
1077#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)]
1079pub struct Synonym {
1080 pub terms: Vec<String>,
1082 #[serde(default = "default_as_true")]
1093 pub multiway: bool,
1094}
1095
1096fn default_as_true() -> bool {
1097 true
1098}
1099
1100#[derive(Debug, Clone, Deserialize, Serialize, ToSchema, Default)]
1102pub struct SchemaField {
1103 pub field: String,
1105 pub store: bool,
1107 pub index_lexical: bool,
1110 #[serde(skip_serializing_if = "is_default_bool")]
1113 #[serde(default = "default_false")]
1114 pub index_vector: bool,
1115 pub field_type: FieldType,
1117 #[serde(skip_serializing_if = "is_default_bool")]
1122 #[serde(default = "default_false")]
1123 pub facet: bool,
1124
1125 #[serde(skip_serializing_if = "is_default_bool")]
1129 #[serde(default = "default_false")]
1130 pub longest: bool,
1131
1132 #[serde(skip_serializing_if = "is_default_f32")]
1134 #[serde(default = "default_1")]
1135 pub boost: f32,
1136
1137 #[serde(skip_serializing_if = "is_default_bool")]
1140 #[serde(default = "default_false")]
1141 pub dictionary_source: bool,
1142
1143 #[serde(skip_serializing_if = "is_default_bool")]
1148 #[serde(default = "default_false")]
1149 pub completion_source: bool,
1150
1151 #[serde(skip)]
1152 pub(crate) indexed_field_id: usize,
1153 #[serde(skip_deserializing)]
1154 pub(crate) field_id: usize,
1155}
1156
1157impl SchemaField {
1177 #[allow(clippy::too_many_arguments)]
1179 pub fn new(
1180 field: String,
1181 store: bool,
1182 index_lexical: bool,
1183 index_vector: bool,
1184 field_type: FieldType,
1185 facet: bool,
1186 longest: bool,
1187 boost: f32,
1188 dictionary_source: bool,
1189 completion_source: bool,
1190 ) -> Self {
1191 SchemaField {
1192 field,
1193 store,
1194 index_lexical,
1195 index_vector,
1196 field_type,
1197 facet,
1198 longest,
1199 boost,
1200 dictionary_source,
1201 completion_source,
1202
1203 indexed_field_id: 0,
1204 field_id: 0,
1205 }
1206 }
1207}
1208
1209fn default_false() -> bool {
1210 false
1211}
1212
1213fn is_default_bool(num: &bool) -> bool {
1214 !(*num)
1215}
1216
1217fn default_1() -> f32 {
1218 1.0
1219}
1220
1221fn is_default_f32(num: &f32) -> bool {
1222 *num == 1.0
1223}
1224
1225pub(crate) struct IndexedField {
1226 pub schema_field_name: String,
1227 pub field_length_sum: usize,
1228 pub indexed_field_id: usize,
1229
1230 pub is_longest_field: bool,
1231}
1232
1233#[derive(Debug, Clone, Deserialize, Serialize, Default, ToSchema)]
1239pub enum StopwordType {
1240 #[default]
1242 None,
1243 English,
1245 German,
1247 French,
1249 Spanish,
1251 Custom {
1253 terms: Vec<String>,
1255 },
1256}
1257
1258#[derive(Debug, Clone, Deserialize, Serialize, Default, ToSchema)]
1262pub enum FrequentwordType {
1263 None,
1265 #[default]
1267 English,
1268 German,
1270 French,
1272 Spanish,
1274 Custom {
1276 terms: Vec<String>,
1278 },
1279}
1280
1281#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)]
1283pub struct SpellingCorrection {
1284 pub max_dictionary_edit_distance: usize,
1286 pub term_length_threshold: Option<Vec<usize>>,
1291
1292 pub count_threshold: usize,
1299
1300 pub max_dictionary_entries: usize,
1305}
1306
1307#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)]
1309pub struct QueryCompletion {
1310 pub max_completion_entries: usize,
1313}
1314
1315#[derive(Clone, Copy, Debug, Deserialize, Serialize, Default, ToSchema)]
1317pub enum Clustering {
1318 None,
1320 #[default]
1322 Auto,
1323 Fixed(usize),
1325}
1326
1327impl fmt::Display for Clustering {
1328 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1329 match self {
1330 Clustering::None => write!(f, "None"),
1331 Clustering::Auto => write!(f, "Auto"),
1332 Clustering::Fixed(value) => write!(f, "Fixed({})", value),
1333 }
1334 }
1335}
1336
1337#[derive(Debug, Clone, Deserialize, Serialize)]
1339pub struct IndexMetaObject {
1340 pub id: u64,
1344 pub name: String,
1346 pub lexical_similarity: LexicalSimilarity,
1348 pub tokenizer: TokenizerType,
1350 pub stemmer: StemmerType,
1352
1353 #[serde(default)]
1359 pub stop_words: StopwordType,
1360 #[serde(default)]
1364 pub frequent_words: FrequentwordType,
1365 #[serde(default = "ngram_indexing_default")]
1383 pub ngram_indexing: u8,
1384
1385 #[serde(default = "doc_store_compression_default")]
1387 pub document_compression: DocumentCompression,
1388
1389 pub access_type: AccessType,
1391 #[serde(default)]
1404 pub spelling_correction: Option<SpellingCorrection>,
1405
1406 #[serde(default)]
1411 pub query_completion: Option<QueryCompletion>,
1412
1413 #[serde(default)]
1415 pub clustering: Clustering,
1416
1417 #[serde(default)]
1419 pub inference: Inference,
1420}
1421
1422fn ngram_indexing_default() -> u8 {
1423 NgramSet::NgramFF as u8 | NgramSet::NgramFFF as u8
1424}
1425
1426fn doc_store_compression_default() -> DocumentCompression {
1427 DocumentCompression::Snappy
1428}
1429
1430#[derive(Debug, Clone, Default)]
1431pub(crate) struct ResultFacet {
1432 pub field: String,
1433 pub values: AHashMap<u32, usize>,
1434 pub prefix: String,
1435 pub length: u32,
1436 pub ranges: Ranges,
1437}
1438
1439#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ToSchema)]
1441pub enum DistanceUnit {
1442 Kilometers,
1444 Miles,
1446}
1447
1448#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)]
1450pub struct DistanceField {
1451 pub field: String,
1453 pub distance: String,
1455 pub base: Point,
1457 pub unit: DistanceUnit,
1459}
1460
1461impl Default for DistanceField {
1462 fn default() -> Self {
1463 DistanceField {
1464 field: String::new(),
1465 distance: String::new(),
1466 base: Vec::new(),
1467 unit: DistanceUnit::Kilometers,
1468 }
1469 }
1470}
1471
1472#[derive(Deserialize, Serialize, Debug, Clone, Default)]
1474pub struct MinMaxField {
1475 pub min: ValueType,
1477 pub max: ValueType,
1479}
1480
1481#[derive(Deserialize, Serialize, Debug, Clone, Default, ToSchema)]
1483pub struct MinMaxFieldJson {
1484 pub min: Value,
1486 pub max: Value,
1488}
1489
1490#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq)]
1492pub enum ValueType {
1493 U8(u8),
1495 U16(u16),
1497 U32(u32),
1499 U64(u64),
1501 I8(i8),
1503 I16(i16),
1505 I32(i32),
1507 I64(i64),
1509 Timestamp(i64),
1511 F32(f32),
1513 F64(f64),
1515 Point(Point, DistanceUnit),
1517 #[default]
1519 None,
1520}
1521
1522#[derive(Deserialize, Serialize, Debug, Clone, Default)]
1524pub struct FacetField {
1525 pub name: String,
1527 pub values: IndexMap<String, (Vec<String>, usize)>,
1531
1532 pub min: ValueType,
1534 pub max: ValueType,
1536
1537 #[serde(skip)]
1538 pub(crate) offset: usize,
1539 #[serde(skip)]
1540 pub(crate) field_type: FieldType,
1541}
1542
1543pub type Facet = Vec<(String, usize)>;
1546
1547pub type ShardArc = Arc<RwLock<Shard>>;
1549
1550pub type IndexArc = Arc<RwLock<Index>>;
1552
1553pub struct Shard {
1556 pub index_format_version_major: u16,
1558 pub index_format_version_minor: u16,
1560
1561 pub indexed_doc_count: usize,
1563 pub(crate) indexed_vector_count: usize,
1565 pub(crate) indexed_cluster_count: usize,
1567
1568 pub committed_doc_count: usize,
1570 pub(crate) uncommitted: bool,
1572
1573 pub(crate) modified: bool,
1575
1576 pub schema_map: HashMap<String, SchemaField>,
1578 pub stored_field_names: Vec<String>,
1580 pub meta: IndexMetaObject,
1582
1583 pub(crate) is_last_level_incomplete: bool,
1584 pub(crate) last_level_index_file_start_pos: u64,
1585 pub(crate) last_level_docstore_file_start_pos: u64,
1586 pub(crate) last_level_vector_file_start_pos: u64,
1587
1588 pub(crate) semaphore: Arc<Semaphore>,
1590 pub(crate) docstore_file: File,
1591 pub(crate) docstore_file_mmap: Mmap,
1592
1593 pub(crate) delete_file: File,
1594 pub(crate) delete_hashset: AHashSet<usize>,
1595
1596 pub(crate) index_file: File,
1597 pub(crate) index_path_string: String,
1598 pub(crate) index_file_mmap: Mmap,
1599
1600 pub(crate) compressed_index_segment_block_buffer: Vec<u8>,
1601 pub(crate) compressed_docstore_segment_block_buffer: Vec<u8>,
1602
1603 pub(crate) segment_number1: usize,
1604 pub(crate) segment_number_bits1: usize,
1605
1606 pub(crate) document_length_normalized_average: f32,
1607 pub(crate) positions_sum_normalized: u64,
1608
1609 pub(crate) level_index: Vec<LevelIndex>,
1610 pub(crate) segments_index: Vec<SegmentIndex>,
1611 pub(crate) segments_level0: Vec<SegmentLevel0>,
1612
1613 pub(crate) enable_fallback: bool,
1614 pub(crate) enable_single_term_topk: bool,
1615 pub(crate) enable_search_quality_test: bool,
1616 pub(crate) enable_inter_query_threading: bool,
1617 pub(crate) enable_inter_query_threading_auto: bool,
1618
1619 pub(crate) segment_number_mask1: u32,
1620
1621 pub(crate) indexed_field_vec: Vec<IndexedField>,
1622 pub(crate) indexed_field_id_bits: usize,
1623 pub(crate) indexed_field_id_mask: usize,
1624 pub(crate) longest_field_id: usize,
1625 pub(crate) longest_field_auto: bool,
1626 pub(crate) indexed_schema_vec: Vec<SchemaField>,
1627
1628 pub(crate) document_length_compressed_array: Vec<[u8; ROARING_BLOCK_SIZE]>,
1629 pub(crate) key_count_sum: u64,
1630
1631 pub(crate) block_id: usize,
1632 pub(crate) strip_compressed_sum: u64,
1633 pub(crate) postings_buffer: Vec<u8>,
1634 pub(crate) postings_buffer_pointer: usize,
1635
1636 pub(crate) size_compressed_positions_index: u64,
1637 pub(crate) size_compressed_docid_index: u64,
1638
1639 pub(crate) postinglist_count: usize,
1640 pub(crate) docid_count: usize,
1641 pub(crate) position_count: usize,
1642
1643 pub(crate) mute: bool,
1644 pub(crate) frequentword_results: AHashMap<String, ResultObject>,
1645
1646 pub(crate) facets: Vec<FacetField>,
1647 pub(crate) facets_map: AHashMap<String, usize>,
1648 pub(crate) facets_size_sum: usize,
1649 pub(crate) facets_file: File,
1650 pub(crate) facets_file_mmap: MmapMut,
1651 pub(crate) bm25_component_cache: [f32; 256],
1652
1653 pub(crate) string_set_to_single_term_id_vec: Vec<AHashMap<String, AHashSet<u32>>>,
1654
1655 pub(crate) synonyms_map: AHashMap<u64, SynonymItem>,
1656
1657 #[cfg(feature = "zh")]
1658 pub(crate) word_segmentation_option: Option<WordSegmentationTM>,
1659
1660 pub(crate) shard_number: usize,
1661 pub(crate) index_option: Option<Arc<RwLock<Index>>>,
1662 pub(crate) stemmer: Option<Stemmer>,
1663
1664 pub(crate) stop_words: AHashSet<String>,
1665 pub(crate) frequent_words: Vec<String>,
1666 pub(crate) frequent_hashset: AHashSet<u64>,
1667 pub(crate) key_head_size: usize,
1668 pub(crate) level_terms: AHashMap<u32, String>,
1669 pub(crate) level_completions: Arc<RwLock<AHashMap<Vec<String>, usize>>>,
1670 pub(crate) is_avx2: bool,
1672 pub(crate) is_neon: bool,
1674 pub(crate) is_simd: bool,
1677 pub(crate) is_vector_indexing: bool,
1678 pub(crate) is_lexical_indexing: bool,
1679 pub(crate) chunks_meta: Vec<(u16, u32, u32)>,
1680 pub(crate) chunks_string: Vec<String>,
1681 pub(crate) vector_file: File,
1682 pub(crate) vector_file_mmap: Mmap,
1683 pub(crate) block_vector_buffer: Vec<ParentMedoid>,
1684 pub(crate) vector_dimensions: usize,
1685 pub(crate) vector_dimensions_original: usize,
1686 pub(crate) vector_precision: Precision,
1687 pub(crate) quantization: Quantization,
1688 pub(crate) vector_similarity: VectorSimilarity,
1689 pub(crate) chunk_size: usize,
1690
1691 pub(crate) min_vector_value: f32,
1692 pub(crate) max_vector_value: f32,
1693 pub(crate) turbo_quant: TurboQuant,
1694}
1695
1696pub struct Index {
1699 pub(crate) docid_global: Arc<RwLock<usize>>,
1700
1701 pub index_format_version_major: u16,
1703 pub index_format_version_minor: u16,
1705
1706 pub(crate) indexed_doc_count: usize,
1708 pub indexed_vector_count: usize,
1710 pub indexed_cluster_count: usize,
1712
1713 pub(crate) deleted_doc_count: usize,
1715 pub schema_map: HashMap<String, SchemaField>,
1717 pub stored_field_names: Vec<String>,
1719 pub meta: IndexMetaObject,
1721
1722 pub(crate) index_file: File,
1723 pub(crate) index_path_string: String,
1724
1725 pub(crate) compressed_index_segment_block_buffer: Vec<u8>,
1726
1727 pub(crate) segment_number1: usize,
1728 pub(crate) segment_number_mask1: u32,
1729
1730 pub(crate) indexed_field_vec: Vec<IndexedField>,
1731
1732 pub(crate) mute: bool,
1733
1734 pub(crate) facets: Vec<FacetField>,
1735
1736 pub(crate) synonyms_map: AHashMap<u64, SynonymItem>,
1737
1738 pub(crate) shard_number: usize,
1739 pub(crate) shard_vec: Vec<Arc<RwLock<Shard>>>,
1740
1741 pub(crate) max_dictionary_entries: usize,
1742 pub(crate) symspell_option: Option<Arc<RwLock<SymSpell>>>,
1743
1744 pub(crate) max_completion_entries: usize,
1745 pub(crate) completion_option: Option<Arc<RwLock<PruningRadixTrie>>>,
1746
1747 pub(crate) frequent_hashset: AHashSet<String>,
1748
1749 pub(crate) embedding_model_option: Option<StaticModel>,
1750 pub vector_precision: Precision,
1752 pub(crate) quantization: Quantization,
1753 pub vector_dimensions: usize,
1756 pub vector_dimensions_original: usize,
1758 pub vector_similarity: VectorSimilarity,
1760 pub(crate) is_avx2: bool,
1762 pub(crate) is_neon: bool,
1764 pub(crate) is_simd: bool,
1766 pub(crate) is_vector_indexing: bool,
1768 pub(crate) is_lexical_indexing: bool,
1770 pub(crate) chunk_size: usize,
1771 pub(crate) turbo_quant: TurboQuant,
1772}
1773
1774pub type SynonymItem = Vec<(String, (u64, u32))>;
1776
1777pub fn version() -> &'static str {
1779 VERSION
1780}
1781
1782pub(crate) fn get_synonyms_map(
1783 synonyms: &[Synonym],
1784 segment_number_mask1: u32,
1785) -> AHashMap<u64, SynonymItem> {
1786 let mut synonyms_map: AHashMap<u64, SynonymItem> = AHashMap::new();
1787 for synonym in synonyms.iter() {
1788 if synonym.terms.len() > 1 {
1789 let mut hashes: Vec<(String, (u64, u32))> = Vec::new();
1790 for term in synonym.terms.iter() {
1791 let term_bytes = term.to_lowercase();
1792 hashes.push((
1793 term.to_string(),
1794 (
1795 hash64(term_bytes.as_bytes()),
1796 hash32(term_bytes.as_bytes()) & segment_number_mask1,
1797 ),
1798 ));
1799 }
1800 if synonym.multiway {
1801 for (i, hash) in hashes.iter().enumerate() {
1802 let new_synonyms = if i == 0 {
1803 hashes[1..].to_vec()
1804 } else if i == hashes.len() - 1 {
1805 hashes[..hashes.len() - 1].to_vec()
1806 } else {
1807 [&hashes[..i], &hashes[(i + 1)..]].concat()
1808 };
1809
1810 if let Some(item) = synonyms_map.get_mut(&hash.1.0) {
1811 *item = item
1812 .clone()
1813 .into_iter()
1814 .chain(new_synonyms)
1815 .collect::<HashMap<String, (u64, u32)>>()
1816 .into_iter()
1817 .collect();
1818 } else {
1819 synonyms_map.insert(hash.1.0, new_synonyms);
1820 }
1821 }
1822 } else {
1823 synonyms_map.insert(hashes[0].1.0, hashes[1..].to_vec());
1824 }
1825 }
1826 }
1827 synonyms_map
1828}
1829
1830#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, FromPrimitive)]
1834pub enum NgramSet {
1835 SingleTerm = 0b00000000,
1837 NgramFF = 0b00000001,
1839 NgramFR = 0b00000010,
1841 NgramRF = 0b00000100,
1843 NgramFFF = 0b00001000,
1845 NgramRFF = 0b00010000,
1847 NgramFFR = 0b00100000,
1849 NgramFRF = 0b01000000,
1851}
1852
1853#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, FromPrimitive, Default)]
1854pub(crate) enum NgramType {
1855 #[default]
1857 SingleTerm = 0,
1858 NgramFF = 1,
1860 NgramFR = 2,
1862 NgramRF = 3,
1864 NgramFFF = 4,
1866 NgramRFF = 5,
1868 NgramFFR = 6,
1870 NgramFRF = 7,
1872}
1873
1874pub async fn create_index(
1887 index_path: &Path,
1888 meta: IndexMetaObject,
1889 schema: &Vec<SchemaField>,
1890 synonyms: &Vec<Synonym>,
1891 segment_number_bits1: usize,
1892 mute: bool,
1893 force_shard_number: Option<usize>,
1894) -> Result<IndexArc, String> {
1895 create_index_root(
1896 index_path,
1897 meta,
1898 schema,
1899 true,
1900 synonyms,
1901 segment_number_bits1,
1902 mute,
1903 force_shard_number,
1904 )
1905 .await
1906}
1907
1908#[allow(clippy::too_many_arguments)]
1909pub(crate) async fn create_index_root(
1910 index_path: &Path,
1911 meta: IndexMetaObject,
1912 #[allow(clippy::ptr_arg)] schema: &Vec<SchemaField>,
1913 serialize_schema: bool,
1914 synonyms: &Vec<Synonym>,
1915 segment_number_bits1: usize,
1916 mute: bool,
1917 force_shard_number: Option<usize>,
1918) -> Result<IndexArc, String> {
1919 let frequent_hashset: AHashSet<String> = match &meta.frequent_words {
1920 FrequentwordType::None => AHashSet::new(),
1921 FrequentwordType::English => FREQUENT_EN.lines().map(|x| x.to_string()).collect(),
1922 FrequentwordType::German => FREQUENT_EN.lines().map(|x| x.to_string()).collect(),
1923 FrequentwordType::French => FREQUENT_FR.lines().map(|x| x.to_string()).collect(),
1924 FrequentwordType::Spanish => FREQUENT_ES.lines().map(|x| x.to_string()).collect(),
1925 FrequentwordType::Custom { terms } => terms.iter().map(|x| x.to_string()).collect(),
1926 };
1927
1928 let segment_number1 = 1usize << segment_number_bits1;
1929 let segment_number_mask1 = (1u32 << segment_number_bits1) - 1;
1930
1931 let index_path_buf = index_path.to_path_buf();
1932 let index_path_string = index_path_buf.to_str().unwrap();
1933
1934 if !index_path.exists() {
1935 if !mute {
1936 println!("index path created: {} ", index_path_string);
1937 }
1938 fs::create_dir_all(index_path).unwrap();
1939 }
1940
1941 let file_path = Path::new(index_path_string).join(FILE_PATH);
1942 if !file_path.exists() {
1943 fs::create_dir_all(file_path).unwrap();
1944 }
1945
1946 match File::options()
1947 .read(true)
1948 .write(true)
1949 .create(true)
1950 .truncate(false)
1951 .open(Path::new(index_path).join(INDEX_FILENAME))
1952 {
1953 Ok(index_file) => {
1954 let mut is_vector_indexing = false;
1955 let mut is_lexical_indexing = false;
1956 let mut schema = schema.clone();
1957 for schema_field in schema.iter_mut() {
1958 if schema_field.field_type == FieldType::Binary && schema_field.index_lexical {
1959 schema_field.index_lexical = false;
1960 }
1961 if schema_field.index_vector {
1962 is_vector_indexing = true;
1963 }
1964 if schema_field.index_lexical {
1965 is_lexical_indexing = true;
1966 }
1967 }
1968
1969 let mut document_length_compressed_array: Vec<[u8; ROARING_BLOCK_SIZE]> = Vec::new();
1970 let mut indexed_field_vec: Vec<IndexedField> = Vec::new();
1971 let mut facets_vec: Vec<FacetField> = Vec::new();
1972 let mut facets_map: AHashMap<String, usize> = AHashMap::new();
1973
1974 let mut schema_map: HashMap<String, SchemaField> = HashMap::new();
1975 let mut indexed_schema_vec: Vec<SchemaField> = Vec::new();
1976 let mut stored_field_names = Vec::new();
1977 let mut facets_size_sum = 0;
1978 let mut longest_field_id_option: Option<usize> = None;
1979 for (i, schema_field) in schema.iter().enumerate() {
1980 let mut schema_field_clone = schema_field.clone();
1981
1982 schema_field_clone.indexed_field_id = indexed_field_vec.len();
1983 if schema_field.longest && schema_field.index_lexical {
1984 longest_field_id_option = Some(schema_field_clone.indexed_field_id);
1985 }
1986
1987 schema_field_clone.field_id = i;
1988 schema_map.insert(schema_field.field.clone(), schema_field_clone.clone());
1989
1990 if schema_field.facet {
1991 let facet_size = match schema_field.field_type {
1992 FieldType::U8 => 1,
1993 FieldType::U16 => 2,
1994 FieldType::U32 => 4,
1995 FieldType::U64 => 8,
1996 FieldType::I8 => 1,
1997 FieldType::I16 => 2,
1998 FieldType::I32 => 4,
1999 FieldType::I64 => 8,
2000 FieldType::Timestamp => 8,
2001 FieldType::F32 => 4,
2002 FieldType::F64 => 8,
2003 FieldType::String16 => 2,
2004 FieldType::String32 => 4,
2005 FieldType::StringSet16 => 2,
2006 FieldType::StringSet32 => 4,
2007 FieldType::Point => 8,
2008 _ => 1,
2009 };
2010
2011 facets_map.insert(schema_field.field.clone(), facets_vec.len());
2012 facets_vec.push(FacetField {
2013 name: schema_field.field.clone(),
2014 values: IndexMap::new(),
2015 min: ValueType::None,
2016 max: ValueType::None,
2017 offset: facets_size_sum,
2018 field_type: schema_field.field_type.clone(),
2019 });
2020 facets_size_sum += facet_size;
2021 }
2022
2023 if schema_field.index_lexical || schema_field.index_vector {
2024 indexed_field_vec.push(IndexedField {
2025 schema_field_name: schema_field.field.clone(),
2026 is_longest_field: false,
2027 field_length_sum: 0,
2028 indexed_field_id: indexed_field_vec.len(),
2029 });
2030 indexed_schema_vec.push(schema_field_clone);
2031 document_length_compressed_array.push([0; ROARING_BLOCK_SIZE]);
2032 }
2033
2034 if schema_field.store {
2035 stored_field_names.push(schema_field.field.clone());
2036 }
2037 }
2038
2039 if !facets_vec.is_empty()
2040 && let Ok(file) = File::open(Path::new(index_path).join(FACET_VALUES_FILENAME))
2041 && let Ok(facets) = serde_json::from_reader(BufReader::new(file))
2042 {
2043 let mut facets: Vec<FacetField> = facets;
2044 if facets_vec.len() == facets.len() {
2045 for i in 0..facets.len() {
2046 facets[i].offset = facets_vec[i].offset;
2047 facets[i].field_type = facets_vec[i].field_type.clone();
2048 }
2049 }
2050 facets_vec = facets;
2051 }
2052
2053 let synonyms_map = get_synonyms_map(synonyms, segment_number_mask1);
2054
2055 let shard_number = if let Some(shard_number) = force_shard_number {
2056 shard_number
2057 } else {
2058 cmp::min(
2059 available_parallelism()
2060 .map(|n| n.get())
2061 .unwrap_or_else(|_| num_cpus::get_physical()),
2062 num_cpus::get_physical(),
2063 )
2064 };
2065
2066 let (
2067 vector_dimensions,
2068 embedding_model_option,
2069 vector_precision,
2070 chunk_size,
2071 quantization,
2072 vector_similarity,
2073 ) = if is_vector_indexing {
2074 let (
2075 dimensions,
2076 model_path,
2077 precision,
2078 chunk_size,
2079 quantization,
2080 vector_similarity,
2081 ) = match &meta.inference {
2082 Inference::Model2Vec {
2083 model,
2084 chunk_size,
2085 quantization,
2086 } => {
2087 let chunk_size = *chunk_size.max(&10);
2088 match model {
2089 Model::PotionBase2M => (
2090 0,
2091 "minishlab/potion-base-2M",
2092 Precision::F32,
2093 chunk_size,
2094 *quantization,
2095 VectorSimilarity::Cosine,
2096 ),
2097 Model::PotionBase4M => (
2098 0,
2099 "minishlab/potion-base-4M",
2100 Precision::F32,
2101 chunk_size,
2102 *quantization,
2103 VectorSimilarity::Cosine,
2104 ),
2105 Model::PotionBase8M => (
2106 0,
2107 "minishlab/potion-base-8M",
2108 Precision::F32,
2109 chunk_size,
2110 *quantization,
2111 VectorSimilarity::Cosine,
2112 ),
2113 Model::PotionBase32M => (
2114 0,
2115 "minishlab/potion-base-32M",
2116 Precision::F32,
2117 chunk_size,
2118 *quantization,
2119 VectorSimilarity::Cosine,
2120 ),
2121 Model::PotionMultilingual128M => (
2122 0,
2123 "minishlab/potion-multilingual-128M",
2124 Precision::F32,
2125 chunk_size,
2126 *quantization,
2127 VectorSimilarity::Cosine,
2128 ),
2129 Model::PotionRetrieval32M => (
2130 0,
2131 "minishlab/potion-retrieval-32M",
2132 Precision::F32,
2133 chunk_size,
2134 *quantization,
2135 VectorSimilarity::Cosine,
2136 ),
2137 Model::PotionCode16MV2 => (
2138 0,
2139 "minishlab/potion-code-16M-v2",
2140 Precision::F32,
2141 chunk_size,
2142 *quantization,
2143 VectorSimilarity::Cosine,
2144 ),
2145 }
2146 }
2147 Inference::Model2VecCustom {
2148 path,
2149 chunk_size,
2150 quantization,
2151 } => (
2152 0,
2153 path.as_str(),
2154 Precision::F32,
2155 *chunk_size,
2156 *quantization,
2157 VectorSimilarity::Cosine,
2158 ),
2159 Inference::External {
2160 dimensions: vector_dimensions,
2161 precision: vector_precision,
2162 quantization: vector_quantization,
2163 similarity,
2164 } => (
2165 *vector_dimensions,
2166 "",
2167 *vector_precision,
2168 0,
2169 *vector_quantization,
2170 *similarity,
2171 ),
2172 Inference::None => (
2173 0,
2174 "",
2175 Precision::None,
2176 0,
2177 Quantization::None,
2178 VectorSimilarity::Cosine,
2179 ),
2180 };
2181
2182 if !model_path.is_empty() {
2183 let model =
2184 Some(StaticModel::from_pretrained(model_path, None, None, None).unwrap());
2185 let dimensions = model.as_ref().unwrap().encode(&["test".to_string()])[0].len();
2186 (
2187 dimensions,
2188 model,
2189 precision,
2190 chunk_size,
2191 quantization,
2192 VectorSimilarity::Cosine,
2193 )
2194 } else {
2195 (
2196 dimensions,
2197 None,
2198 precision,
2199 chunk_size,
2200 quantization,
2201 vector_similarity,
2202 )
2203 }
2204 } else {
2205 (
2206 0,
2207 None,
2208 Precision::None,
2209 0,
2210 Quantization::None,
2211 VectorSimilarity::Cosine,
2212 )
2213 };
2214
2215 let turbo_quant = if quantization == Quantization::TurboQuantI8 {
2216 TurboQuant::new(vector_dimensions, 1234)
2217 } else {
2218 TurboQuant::new(0, 1234)
2219 };
2220
2221 let vector_dimensions_original = vector_dimensions;
2222 let vector_dimensions = if quantization == Quantization::TurboQuantI8
2223 && vector_precision == Precision::F32
2224 {
2225 TurboQuant::next_power_of_two(vector_dimensions)
2226 } else {
2227 vector_dimensions
2228 };
2229
2230 let mut shard_vec: Vec<Arc<RwLock<Shard>>> = Vec::new();
2231 if serialize_schema {
2232 let mut result_object_list = Vec::new();
2233 let index_path_clone = Arc::new(index_path.to_path_buf());
2234 for i in 0..shard_number {
2235 let index_path_clone2 = index_path_clone.clone();
2236 let meta_clone = meta.clone();
2237 let schema_clone = schema.clone();
2238 let turbo_quant_clone = turbo_quant.clone();
2239 result_object_list.push(tokio::spawn(async move {
2240 let shard_path = index_path_clone2.join("shards").join(i.to_string());
2241 let mut shard_meta = meta_clone.clone();
2242 shard_meta.id = i as u64;
2243
2244 let mut shard = create_shard(
2245 &shard_path,
2246 &shard_meta,
2247 &schema_clone,
2248 serialize_schema,
2249 &Vec::new(),
2250 segment_number_bits1,
2251 mute,
2252 longest_field_id_option,
2253 )
2254 .unwrap();
2255 shard.shard_number = shard_number;
2256 shard.vector_dimensions = vector_dimensions;
2257 shard.vector_dimensions_original = vector_dimensions_original;
2258 shard.vector_precision = vector_precision;
2259 shard.quantization = quantization;
2260 shard.vector_similarity = vector_similarity;
2261 shard.is_avx2 = *IS_AVX2;
2262 shard.is_neon = *IS_NEON;
2263 shard.is_simd = *IS_SIMD;
2264 shard.chunk_size = chunk_size;
2265 shard.turbo_quant = turbo_quant_clone;
2266
2267 let shard_arc = Arc::new(RwLock::new(shard));
2268 (shard_arc, i)
2269 }));
2270 }
2271 for result_object_shard in result_object_list {
2272 let ro_shard = result_object_shard.await.unwrap();
2273 shard_vec.push(ro_shard.0);
2274 }
2275 }
2276
2277 let mut index = Index {
2278 docid_global: Arc::new(RwLock::new(0)),
2279 index_format_version_major: INDEX_FORMAT_VERSION_MAJOR,
2280 index_format_version_minor: INDEX_FORMAT_VERSION_MINOR,
2281
2282 index_file,
2283 index_path_string: index_path_string.to_owned(),
2284 stored_field_names,
2285
2286 compressed_index_segment_block_buffer: vec![0; 10_000_000],
2287 indexed_doc_count: 0,
2288 indexed_vector_count: 0,
2289 indexed_cluster_count: 0,
2290 deleted_doc_count: 0,
2291 segment_number1: 0,
2292 segment_number_mask1: 0,
2293 schema_map,
2294 indexed_field_vec,
2295 meta: meta.clone(),
2296 mute,
2297 facets: facets_vec,
2298 synonyms_map,
2299
2300 shard_number,
2301 shard_vec,
2302
2303 max_dictionary_entries: if let Some(spelling_correction) = &meta.spelling_correction
2304 {
2305 spelling_correction.max_dictionary_entries
2306 } else {
2307 usize::MAX
2308 },
2309
2310 symspell_option: if let Some(spelling_correction) = meta.spelling_correction {
2311 Some(Arc::new(RwLock::new(SymSpell::new(
2312 spelling_correction.max_dictionary_edit_distance,
2313 spelling_correction.term_length_threshold,
2314 7,
2315 spelling_correction.count_threshold,
2316 ))))
2317 } else {
2318 None
2319 },
2320
2321 max_completion_entries: if let Some(query_completion) = &meta.query_completion {
2322 query_completion.max_completion_entries
2323 } else {
2324 usize::MAX
2325 },
2326
2327 completion_option: meta
2328 .query_completion
2329 .as_ref()
2330 .map(|_query_completion| Arc::new(RwLock::new(PruningRadixTrie::new()))),
2331
2332 frequent_hashset,
2333
2334 embedding_model_option,
2335 vector_dimensions,
2336 vector_dimensions_original,
2337 vector_precision,
2338 quantization,
2339 vector_similarity,
2340 is_avx2: *IS_AVX2,
2341 is_neon: *IS_NEON,
2342 is_simd: *IS_SIMD,
2343 is_vector_indexing,
2344 is_lexical_indexing,
2345 chunk_size,
2346 turbo_quant,
2347 };
2348
2349 let file_len = index.index_file.metadata().unwrap().len();
2350 if file_len == 0 {
2351 write_u16(
2352 INDEX_FORMAT_VERSION_MAJOR,
2353 &mut index.compressed_index_segment_block_buffer,
2354 0,
2355 );
2356 write_u16(
2357 INDEX_FORMAT_VERSION_MINOR,
2358 &mut index.compressed_index_segment_block_buffer,
2359 2,
2360 );
2361 let _ = index.index_file.write(
2362 &index.compressed_index_segment_block_buffer[0..INDEX_HEADER_SIZE as usize],
2363 );
2364 } else {
2365 let _ = index.index_file.read(
2366 &mut index.compressed_index_segment_block_buffer[0..INDEX_HEADER_SIZE as usize],
2367 );
2368 index.index_format_version_major =
2369 read_u16(&index.compressed_index_segment_block_buffer, 0);
2370 index.index_format_version_minor =
2371 read_u16(&index.compressed_index_segment_block_buffer, 2);
2372
2373 if INDEX_FORMAT_VERSION_MAJOR != index.index_format_version_major {
2374 return Err("incompatible index format version ".to_string()
2375 + &INDEX_FORMAT_VERSION_MAJOR.to_string()
2376 + " "
2377 + &index.index_format_version_major.to_string());
2378 };
2379
2380 if index.index_format_version_major == 6 && index.index_format_version_minor == 0 {
2381 index.meta.document_compression = DocumentCompression::Zstd;
2382 }
2383 }
2384
2385 index.segment_number1 = segment_number1;
2386 index.segment_number_mask1 = segment_number_mask1;
2387
2388 if serialize_schema {
2389 serde_json::to_writer(
2390 &File::create(Path::new(index_path).join(SCHEMA_FILENAME)).unwrap(),
2391 &schema,
2392 )
2393 .unwrap();
2394
2395 if !synonyms.is_empty() {
2396 serde_json::to_writer(
2397 &File::create(Path::new(index_path).join(SYNONYMS_FILENAME)).unwrap(),
2398 &synonyms,
2399 )
2400 .unwrap();
2401 }
2402
2403 serde_json::to_writer(
2404 &File::create(Path::new(index_path).join(META_FILENAME)).unwrap(),
2405 &index.meta,
2406 )
2407 .unwrap();
2408 }
2409
2410 let index_arc = Arc::new(RwLock::new(index));
2411
2412 if serialize_schema {
2413 for shard in index_arc.write().await.shard_vec.iter() {
2414 shard.write().await.index_option = Some(index_arc.clone());
2415 }
2416 }
2417
2418 Ok(index_arc)
2419 }
2420 Err(e) => {
2421 println!("file opening error");
2422 Err(e.to_string())
2423 }
2424 }
2425}
2426
2427#[allow(clippy::too_many_arguments)]
2428pub(crate) fn create_shard(
2429 index_path: &Path,
2430 meta: &IndexMetaObject,
2431 schema: &Vec<SchemaField>,
2432 serialize_schema: bool,
2433 synonyms: &Vec<Synonym>,
2434 segment_number_bits1: usize,
2435 mute: bool,
2436 longest_field_id_option: Option<usize>,
2437) -> Result<Shard, String> {
2438 let segment_number1 = 1usize << segment_number_bits1;
2439 let segment_number_mask1 = (1u32 << segment_number_bits1) - 1;
2440
2441 let index_path_buf = index_path.to_path_buf();
2442 let index_path_string = index_path_buf.to_str().unwrap();
2443
2444 if !index_path.exists() {
2445 fs::create_dir_all(index_path).unwrap();
2446 }
2447
2448 let file_path = Path::new(index_path_string).join(FILE_PATH);
2449 if !file_path.exists() {
2450 fs::create_dir_all(file_path).unwrap();
2451 }
2452
2453 match File::options()
2454 .read(true)
2455 .write(true)
2456 .create(true)
2457 .truncate(false)
2458 .open(Path::new(index_path).join(INDEX_FILENAME))
2459 {
2460 Ok(index_file) => {
2461 let docstore_file = File::options()
2462 .read(true)
2463 .write(true)
2464 .create(true)
2465 .truncate(false)
2466 .open(Path::new(index_path).join(DOCSTORE_FILENAME))
2467 .unwrap();
2468
2469 let delete_file = File::options()
2470 .read(true)
2471 .write(true)
2472 .create(true)
2473 .truncate(false)
2474 .open(Path::new(index_path).join(DELETE_FILENAME))
2475 .unwrap();
2476
2477 let facets_file = File::options()
2478 .read(true)
2479 .write(true)
2480 .create(true)
2481 .truncate(false)
2482 .open(Path::new(index_path).join(FACET_FILENAME))
2483 .unwrap();
2484
2485 let vector_file = File::options()
2486 .read(true)
2487 .write(true)
2488 .create(true)
2489 .truncate(false)
2490 .open(Path::new(index_path).join(VECTOR_FILENAME))
2491 .unwrap();
2492
2493 let mut document_length_compressed_array: Vec<[u8; ROARING_BLOCK_SIZE]> = Vec::new();
2494 let mut indexed_field_vec: Vec<IndexedField> = Vec::new();
2495 let mut facets_vec: Vec<FacetField> = Vec::new();
2496 let mut facets_map: AHashMap<String, usize> = AHashMap::new();
2497
2498 let mut schema_map: HashMap<String, SchemaField> = HashMap::new();
2499 let mut indexed_schema_vec: Vec<SchemaField> = Vec::new();
2500 let mut stored_fields_flag = false;
2501 let mut is_vector_indexing = false;
2502 let mut is_lexical_indexing = false;
2503 let mut stored_field_names = Vec::new();
2504 let mut facets_size_sum = 0;
2505 for (i, schema_field) in schema.iter().enumerate() {
2506 if schema_field.index_vector {
2507 is_vector_indexing = true;
2508 }
2509 if schema_field.index_lexical {
2510 is_lexical_indexing = true;
2511 }
2512 let mut schema_field_clone = schema_field.clone();
2513
2514 schema_field_clone.indexed_field_id = indexed_field_vec.len();
2515
2516 schema_field_clone.field_id = i;
2517 schema_map.insert(schema_field.field.clone(), schema_field_clone.clone());
2518
2519 if schema_field.facet {
2520 let facet_size = match schema_field.field_type {
2521 FieldType::U8 => 1,
2522 FieldType::U16 => 2,
2523 FieldType::U32 => 4,
2524 FieldType::U64 => 8,
2525 FieldType::I8 => 1,
2526 FieldType::I16 => 2,
2527 FieldType::I32 => 4,
2528 FieldType::I64 => 8,
2529 FieldType::Timestamp => 8,
2530 FieldType::F32 => 4,
2531 FieldType::F64 => 8,
2532 FieldType::String16 => 2,
2533 FieldType::String32 => 4,
2534 FieldType::StringSet16 => 2,
2535 FieldType::StringSet32 => 4,
2536 FieldType::Point => 8,
2537 _ => 1,
2538 };
2539
2540 facets_map.insert(schema_field.field.clone(), facets_vec.len());
2541 facets_vec.push(FacetField {
2542 name: schema_field.field.clone(),
2543 values: IndexMap::new(),
2544 min: ValueType::None,
2545 max: ValueType::None,
2546 offset: facets_size_sum,
2547 field_type: schema_field.field_type.clone(),
2548 });
2549 facets_size_sum += facet_size;
2550 }
2551
2552 if schema_field.index_lexical || schema_field.index_vector {
2553 indexed_field_vec.push(IndexedField {
2554 schema_field_name: schema_field.field.clone(),
2555 is_longest_field: false,
2556 field_length_sum: 0,
2557 indexed_field_id: indexed_field_vec.len(),
2558 });
2559 indexed_schema_vec.push(schema_field_clone);
2560 document_length_compressed_array.push([0; ROARING_BLOCK_SIZE]);
2561 }
2562
2563 if schema_field.store {
2564 stored_fields_flag = true;
2565 stored_field_names.push(schema_field.field.clone());
2566 }
2567 }
2568
2569 let indexed_field_id_bits =
2570 (usize::BITS - (indexed_field_vec.len() - 1).leading_zeros()) as usize;
2571
2572 let index_file_mmap;
2573 let docstore_file_mmap = if meta.access_type == AccessType::Mmap {
2574 index_file_mmap = unsafe { Mmap::map(&index_file).expect("Unable to create Mmap") };
2575 unsafe { Mmap::map(&docstore_file).expect("Unable to create Mmap") }
2576 } else {
2577 index_file_mmap = unsafe {
2578 MmapOptions::new()
2579 .len(0)
2580 .map(&index_file)
2581 .expect("Unable to create Mmap")
2582 };
2583 unsafe {
2584 MmapOptions::new()
2585 .len(0)
2586 .map(&docstore_file)
2587 .expect("Unable to create Mmap")
2588 }
2589 };
2590
2591 if !facets_vec.is_empty()
2592 && let Ok(file) = File::open(Path::new(index_path).join(FACET_VALUES_FILENAME))
2593 && let Ok(facets) = serde_json::from_reader(BufReader::new(file))
2594 {
2595 let mut facets: Vec<FacetField> = facets;
2596 if facets_vec.len() == facets.len() {
2597 for i in 0..facets.len() {
2598 facets[i].offset = facets_vec[i].offset;
2599 facets[i].field_type = facets_vec[i].field_type.clone();
2600 }
2601 }
2602 facets_vec = facets;
2603 }
2604
2605 let facets_file_mmap = if !facets_vec.is_empty() {
2606 if facets_file.metadata().unwrap().len() == 0 {
2607 facets_file
2608 .set_len((facets_size_sum * ROARING_BLOCK_SIZE) as u64)
2609 .expect("Unable to set len");
2610 }
2611
2612 unsafe { MmapMut::map_mut(&facets_file).expect("Unable to create Mmap") }
2613 } else {
2614 unsafe { MmapMut::map_mut(&facets_file).expect("Unable to create Mmap") }
2615 };
2616
2617 let vector_file_mmap =
2618 unsafe { Mmap::map(&vector_file).expect("Unable to create Mmap") };
2619
2620 let synonyms_map = get_synonyms_map(synonyms, segment_number_mask1);
2621
2622 let facets_len = facets_vec.len();
2623
2624 #[cfg(feature = "zh")]
2625 let word_segmentation_option = if meta.tokenizer == TokenizerType::UnicodeAlphanumericZH
2626 {
2627 let mut word_segmentation = WordSegmentationTM::new();
2628 word_segmentation.load_dictionary(0, 1, true);
2629 Some(word_segmentation)
2630 } else {
2631 None
2632 };
2633
2634 let shard_number = 1;
2635
2636 let stemmer = match meta.stemmer {
2637 StemmerType::Arabic => Some(Stemmer::create(Algorithm::Arabic)),
2638 StemmerType::Armenian => Some(Stemmer::create(Algorithm::Armenian)),
2639 StemmerType::Basque => Some(Stemmer::create(Algorithm::Basque)),
2640 StemmerType::Catalan => Some(Stemmer::create(Algorithm::Catalan)),
2641 StemmerType::Czech => Some(Stemmer::create(Algorithm::Czech)),
2642 StemmerType::Danish => Some(Stemmer::create(Algorithm::Danish)),
2643 StemmerType::Dutch => Some(Stemmer::create(Algorithm::Dutch)),
2644 StemmerType::DutchPorter => Some(Stemmer::create(Algorithm::DutchPorter)),
2645 StemmerType::English => Some(Stemmer::create(Algorithm::English)),
2646 StemmerType::Esperanto => Some(Stemmer::create(Algorithm::Esperanto)),
2647 StemmerType::Estonian => Some(Stemmer::create(Algorithm::Estonian)),
2648 StemmerType::Finnish => Some(Stemmer::create(Algorithm::Finnish)),
2649 StemmerType::French => Some(Stemmer::create(Algorithm::French)),
2650 StemmerType::German => Some(Stemmer::create(Algorithm::German)),
2651 StemmerType::Greek => Some(Stemmer::create(Algorithm::Greek)),
2652 StemmerType::Hindi => Some(Stemmer::create(Algorithm::Hindi)),
2653 StemmerType::Hungarian => Some(Stemmer::create(Algorithm::Hungarian)),
2654 StemmerType::Indonesian => Some(Stemmer::create(Algorithm::Indonesian)),
2655 StemmerType::Irish => Some(Stemmer::create(Algorithm::Irish)),
2656 StemmerType::Italian => Some(Stemmer::create(Algorithm::Italian)),
2657 StemmerType::Lithuanian => Some(Stemmer::create(Algorithm::Lithuanian)),
2658 StemmerType::Lovins => Some(Stemmer::create(Algorithm::Lovins)),
2659 StemmerType::Nepali => Some(Stemmer::create(Algorithm::Nepali)),
2660 StemmerType::Norwegian => Some(Stemmer::create(Algorithm::Norwegian)),
2661 StemmerType::Persian => Some(Stemmer::create(Algorithm::Persian)),
2662 StemmerType::Polish => Some(Stemmer::create(Algorithm::Polish)),
2663 StemmerType::Porter => Some(Stemmer::create(Algorithm::Porter)),
2664 StemmerType::Portuguese => Some(Stemmer::create(Algorithm::Portuguese)),
2665 StemmerType::Romanian => Some(Stemmer::create(Algorithm::Romanian)),
2666 StemmerType::Russian => Some(Stemmer::create(Algorithm::Russian)),
2667 StemmerType::Serbian => Some(Stemmer::create(Algorithm::Serbian)),
2668 StemmerType::Sesotho => Some(Stemmer::create(Algorithm::Sesotho)),
2669 StemmerType::Spanish => Some(Stemmer::create(Algorithm::Spanish)),
2670 StemmerType::Swedish => Some(Stemmer::create(Algorithm::Swedish)),
2671 StemmerType::Tamil => Some(Stemmer::create(Algorithm::Tamil)),
2672 StemmerType::Turkish => Some(Stemmer::create(Algorithm::Turkish)),
2673 StemmerType::Ukrainian => Some(Stemmer::create(Algorithm::Ukrainian)),
2674 StemmerType::Yiddish => Some(Stemmer::create(Algorithm::Yiddish)),
2675 _ => None,
2676 };
2677
2678 let stop_words: AHashSet<String> = match &meta.stop_words {
2679 StopwordType::None => AHashSet::new(),
2680 StopwordType::English => FREQUENT_EN.lines().map(|x| x.to_string()).collect(),
2681 StopwordType::German => FREQUENT_DE.lines().map(|x| x.to_string()).collect(),
2682 StopwordType::French => FREQUENT_FR.lines().map(|x| x.to_string()).collect(),
2683 StopwordType::Spanish => FREQUENT_ES.lines().map(|x| x.to_string()).collect(),
2684 StopwordType::Custom { terms } => terms.iter().map(|x| x.to_string()).collect(),
2685 };
2686
2687 let frequent_words: Vec<String> = match &meta.frequent_words {
2688 FrequentwordType::None => Vec::new(),
2689 FrequentwordType::English => {
2690 let mut words: Vec<String> =
2691 FREQUENT_EN.lines().map(|x| x.to_string()).collect();
2692 words.sort_unstable();
2693 words
2694 }
2695 FrequentwordType::German => {
2696 let mut words: Vec<String> =
2697 FREQUENT_DE.lines().map(|x| x.to_string()).collect();
2698 words.sort_unstable();
2699 words
2700 }
2701 FrequentwordType::French => {
2702 let mut words: Vec<String> =
2703 FREQUENT_FR.lines().map(|x| x.to_string()).collect();
2704 words.sort_unstable();
2705 words
2706 }
2707 FrequentwordType::Spanish => {
2708 let mut words: Vec<String> =
2709 FREQUENT_ES.lines().map(|x| x.to_string()).collect();
2710 words.sort_unstable();
2711 words
2712 }
2713 FrequentwordType::Custom { terms } => {
2714 let mut words: Vec<String> = terms.iter().map(|x| x.to_string()).collect();
2715 words.sort_unstable();
2716 words
2717 }
2718 };
2719
2720 let frequent_hashset: AHashSet<u64> = frequent_words
2721 .iter()
2722 .map(|x| hash64(x.as_bytes()))
2723 .collect();
2724
2725 let mut index = Shard {
2726 semaphore: Arc::new(Semaphore::new(1)),
2727
2728 index_format_version_major: INDEX_FORMAT_VERSION_MAJOR,
2729 index_format_version_minor: INDEX_FORMAT_VERSION_MINOR,
2730 docstore_file,
2731 delete_file,
2732 delete_hashset: AHashSet::new(),
2733 index_file,
2734 index_path_string: index_path_string.to_owned(),
2735 index_file_mmap,
2736 docstore_file_mmap,
2737 stored_field_names,
2738 compressed_index_segment_block_buffer: vec![0; 10_000_000],
2739 compressed_docstore_segment_block_buffer: if stored_fields_flag {
2740 vec![0; ROARING_BLOCK_SIZE * 4]
2741 } else {
2742 Vec::new()
2743 },
2744 document_length_normalized_average: 0.0,
2745 indexed_doc_count: 0,
2746 committed_doc_count: 0,
2747 is_last_level_incomplete: false,
2748 last_level_index_file_start_pos: 0,
2749 last_level_docstore_file_start_pos: 0,
2750 last_level_vector_file_start_pos: 0,
2751 positions_sum_normalized: 0,
2752 segment_number1: 0,
2753 segment_number_bits1,
2754 segment_number_mask1: 0,
2755 level_index: Vec::new(),
2756 segments_index: Vec::new(),
2757 segments_level0: Vec::new(),
2758
2759 uncommitted: false,
2760 modified: false,
2761 enable_fallback: false,
2762 enable_single_term_topk: false,
2763 enable_search_quality_test: false,
2764 enable_inter_query_threading: false,
2765 enable_inter_query_threading_auto: false,
2766 schema_map,
2767 indexed_field_id_bits,
2768 indexed_field_id_mask: (1usize << indexed_field_id_bits) - 1,
2769 longest_field_id: longest_field_id_option.unwrap_or_default(),
2770 longest_field_auto: longest_field_id_option.is_none(),
2771 indexed_field_vec,
2772 indexed_schema_vec,
2773 meta: meta.clone(),
2774 document_length_compressed_array,
2775 key_count_sum: 0,
2776
2777 block_id: 0,
2778 strip_compressed_sum: 0,
2779 postings_buffer: vec![0; POSTING_BUFFER_SIZE],
2780 postings_buffer_pointer: 0,
2781
2782 docid_count: 0,
2783 size_compressed_docid_index: 0,
2784 size_compressed_positions_index: 0,
2785 position_count: 0,
2786 postinglist_count: 0,
2787 mute,
2788 frequentword_results: AHashMap::new(),
2789 facets: facets_vec,
2790 facets_map,
2791 facets_size_sum,
2792 facets_file,
2793 facets_file_mmap,
2794 string_set_to_single_term_id_vec: vec![AHashMap::new(); facets_len],
2795 bm25_component_cache: [0.0; 256],
2796 synonyms_map,
2797 #[cfg(feature = "zh")]
2798 word_segmentation_option,
2799
2800 shard_number,
2801 index_option: None,
2802 stemmer,
2803 stop_words,
2804 frequent_words,
2805 frequent_hashset,
2806 key_head_size: if meta.ngram_indexing == 0 {
2807 20
2808 } else if meta.ngram_indexing < 8 {
2809 22
2810 } else {
2811 23
2812 },
2813 level_terms: AHashMap::new(),
2814 level_completions: Arc::new(RwLock::new(AHashMap::with_capacity(200_000))),
2815
2816 chunks_meta: Vec::new(),
2817 chunks_string: Vec::new(),
2818 vector_file,
2819 vector_file_mmap,
2820 indexed_vector_count: 0,
2821 indexed_cluster_count: 0,
2822 is_vector_indexing,
2823 is_lexical_indexing,
2824 block_vector_buffer: Vec::new(),
2825 vector_dimensions: 0,
2826 vector_dimensions_original: 0,
2827 vector_precision: Precision::None,
2828 quantization: Quantization::None,
2829 vector_similarity: VectorSimilarity::Dot,
2830 is_avx2: false,
2831 is_neon: false,
2832 is_simd: false,
2833 chunk_size: 0,
2834 min_vector_value: f32::MAX,
2835 max_vector_value: f32::MIN,
2836 turbo_quant: TurboQuant::new(0, 1234),
2837 };
2838
2839 let file_len = index.index_file.metadata().unwrap().len();
2840 if file_len == 0 {
2841 write_u16(
2842 INDEX_FORMAT_VERSION_MAJOR,
2843 &mut index.compressed_index_segment_block_buffer,
2844 0,
2845 );
2846 write_u16(
2847 INDEX_FORMAT_VERSION_MINOR,
2848 &mut index.compressed_index_segment_block_buffer,
2849 2,
2850 );
2851 let _ = index.index_file.write(
2852 &index.compressed_index_segment_block_buffer[0..INDEX_HEADER_SIZE as usize],
2853 );
2854 } else {
2855 let _ = index.index_file.read(
2856 &mut index.compressed_index_segment_block_buffer[0..INDEX_HEADER_SIZE as usize],
2857 );
2858 index.index_format_version_major =
2859 read_u16(&index.compressed_index_segment_block_buffer, 0);
2860 index.index_format_version_minor =
2861 read_u16(&index.compressed_index_segment_block_buffer, 2);
2862
2863 if INDEX_FORMAT_VERSION_MAJOR != index.index_format_version_major {
2864 return Err("incompatible index format version ".to_string()
2865 + &INDEX_FORMAT_VERSION_MAJOR.to_string()
2866 + " "
2867 + &index.index_format_version_major.to_string());
2868 };
2869
2870 if index.index_format_version_major == 6 && index.index_format_version_minor == 0 {
2871 index.meta.document_compression = DocumentCompression::Zstd;
2872 }
2873 }
2874
2875 index.segment_number1 = segment_number1;
2876 index.segment_number_mask1 = segment_number_mask1;
2877 index.segments_level0 = vec![
2878 SegmentLevel0 {
2879 segment: AHashMap::with_capacity(SEGMENT_KEY_CAPACITY),
2880 ..Default::default()
2881 };
2882 index.segment_number1
2883 ];
2884
2885 index.segments_index = Vec::new();
2886 for _i in 0..index.segment_number1 {
2887 index.segments_index.push(SegmentIndex {
2888 byte_array_blocks: Vec::new(),
2889 byte_array_blocks_pointer: Vec::new(),
2890 segment: AHashMap::new(),
2891 });
2892 }
2893
2894 if serialize_schema {
2895 serde_json::to_writer(
2896 &File::create(Path::new(index_path).join(SCHEMA_FILENAME)).unwrap(),
2897 &schema,
2898 )
2899 .unwrap();
2900
2901 if !synonyms.is_empty() {
2902 serde_json::to_writer(
2903 &File::create(Path::new(index_path).join(SYNONYMS_FILENAME)).unwrap(),
2904 &synonyms,
2905 )
2906 .unwrap();
2907 }
2908
2909 serde_json::to_writer(
2910 &File::create(Path::new(index_path).join(META_FILENAME)).unwrap(),
2911 &index.meta,
2912 )
2913 .unwrap();
2914 }
2915
2916 Ok(index)
2917 }
2918 Err(e) => {
2919 println!("file opening error");
2920 Err(e.to_string())
2921 }
2922 }
2923}
2924
2925#[inline(always)]
2926pub(crate) fn get_document_length_compressed_mmap(
2927 index: &Shard,
2928 field_id: usize,
2929 block_id: usize,
2930 doc_id_block: usize,
2931) -> u8 {
2932 index.index_file_mmap[index.level_index[block_id].document_length_compressed_array_pointer
2933 + (field_id << 16)
2934 + doc_id_block]
2935}
2936
2937#[allow(clippy::too_many_arguments)]
2938pub(crate) fn get_max_score(
2939 index: &Shard,
2940 segment: &SegmentIndex,
2941 posting_count_ngram_1: u32,
2942 posting_count_ngram_2: u32,
2943 posting_count_ngram_3: u32,
2944 posting_count: u32,
2945 block_id: usize,
2946 max_docid: usize,
2947 max_p_docid: usize,
2948 pointer_pivot_p_docid: usize,
2949 compression_type_pointer: u32,
2950 ngram_type: &NgramType,
2951) -> f32 {
2952 let byte_array = if index.meta.access_type == AccessType::Mmap {
2953 &index.index_file_mmap[segment.byte_array_blocks_pointer[block_id].0
2954 ..segment.byte_array_blocks_pointer[block_id].0
2955 + segment.byte_array_blocks_pointer[block_id].1]
2956 } else {
2957 &segment.byte_array_blocks[block_id]
2958 };
2959
2960 let mut bm25f = 0.0;
2961
2962 let rank_position_pointer_range: u32 =
2963 compression_type_pointer & 0b0011_1111_1111_1111_1111_1111_1111_1111;
2964
2965 let posting_pointer_size_sum;
2966 let rank_position_pointer;
2967 let posting_pointer_size;
2968 let embed_flag;
2969 if max_p_docid < pointer_pivot_p_docid {
2970 posting_pointer_size_sum = max_p_docid as u32 * 2;
2971 rank_position_pointer = read_u16(
2972 byte_array,
2973 rank_position_pointer_range as usize + posting_pointer_size_sum as usize,
2974 ) as u32;
2975 posting_pointer_size = 2;
2976 embed_flag = (rank_position_pointer & 0b10000000_00000000) != 0;
2977 } else {
2978 posting_pointer_size_sum = (max_p_docid as u32) * 3 - pointer_pivot_p_docid as u32;
2979 rank_position_pointer = read_u32(
2980 byte_array,
2981 rank_position_pointer_range as usize + posting_pointer_size_sum as usize,
2982 );
2983 posting_pointer_size = 3;
2984 embed_flag = (rank_position_pointer & 0b10000000_00000000_00000000) != 0;
2985 };
2986
2987 let positions_pointer = if embed_flag {
2988 rank_position_pointer_range as usize + posting_pointer_size_sum as usize
2989 } else {
2990 let pointer_value = if posting_pointer_size == 2 {
2991 rank_position_pointer & 0b01111111_11111111
2992 } else {
2993 rank_position_pointer & 0b01111111_11111111_11111111
2994 } as usize;
2995
2996 rank_position_pointer_range as usize - pointer_value
2997 };
2998
2999 let mut field_vec: SmallVec<[(u16, usize); 2]> = SmallVec::new();
3000 let mut field_vec_ngram1 = SmallVec::new();
3001 let mut field_vec_ngram2 = SmallVec::new();
3002 let mut field_vec_ngram3 = SmallVec::new();
3003
3004 decode_positions_commit(
3005 posting_pointer_size,
3006 embed_flag,
3007 byte_array,
3008 positions_pointer,
3009 ngram_type,
3010 index.indexed_field_vec.len(),
3011 index.indexed_field_id_bits,
3012 index.indexed_field_id_mask,
3013 index.longest_field_id as u16,
3014 &mut field_vec,
3015 &mut field_vec_ngram1,
3016 &mut field_vec_ngram2,
3017 &mut field_vec_ngram3,
3018 );
3019
3020 if ngram_type == &NgramType::SingleTerm
3021 || index.meta.lexical_similarity == LexicalSimilarity::Bm25fProximity
3022 {
3023 let idf = (((index.indexed_doc_count as f32 - posting_count as f32 + 0.5)
3024 / (posting_count as f32 + 0.5))
3025 + 1.0)
3026 .ln();
3027
3028 for field in field_vec.iter() {
3029 let document_length_normalized = DOCUMENT_LENGTH_COMPRESSION[if index.meta.access_type
3030 == AccessType::Mmap
3031 {
3032 get_document_length_compressed_mmap(index, field.0 as usize, block_id, max_docid)
3033 } else {
3034 index.level_index[block_id].document_length_compressed_array[field.0 as usize]
3035 [max_docid]
3036 } as usize] as f32;
3037
3038 let document_length_quotient =
3039 document_length_normalized / index.document_length_normalized_average;
3040
3041 let tf = field.1 as f32;
3042
3043 let weight = index.indexed_schema_vec[field.0 as usize].boost;
3044
3045 bm25f += weight
3046 * idf
3047 * ((tf * (K + 1.0) / (tf + (K * (1.0 - B + (B * document_length_quotient)))))
3048 + SIGMA);
3049 }
3050 } else if ngram_type == &NgramType::NgramFF
3051 || ngram_type == &NgramType::NgramFR
3052 || ngram_type == &NgramType::NgramRF
3053 {
3054 let idf_ngram1 = (((index.indexed_doc_count as f32 - posting_count_ngram_1 as f32 + 0.5)
3055 / (posting_count_ngram_1 as f32 + 0.5))
3056 + 1.0)
3057 .ln();
3058
3059 let idf_ngram2 = (((index.indexed_doc_count as f32 - posting_count_ngram_2 as f32 + 0.5)
3060 / (posting_count_ngram_2 as f32 + 0.5))
3061 + 1.0)
3062 .ln();
3063
3064 for field in field_vec_ngram1.iter() {
3065 let document_length_normalized = DOCUMENT_LENGTH_COMPRESSION[if index.meta.access_type
3066 == AccessType::Mmap
3067 {
3068 get_document_length_compressed_mmap(index, field.0 as usize, block_id, max_docid)
3069 } else {
3070 index.level_index[block_id].document_length_compressed_array[field.0 as usize]
3071 [max_docid]
3072 } as usize] as f32;
3073
3074 let document_length_quotient =
3075 document_length_normalized / index.document_length_normalized_average;
3076
3077 let tf_ngram1 = field.1 as f32;
3078
3079 let weight = index.indexed_schema_vec[field.0 as usize].boost;
3080
3081 bm25f += weight
3082 * idf_ngram1
3083 * ((tf_ngram1 * (K + 1.0)
3084 / (tf_ngram1 + (K * (1.0 - B + (B * document_length_quotient)))))
3085 + SIGMA);
3086 }
3087
3088 for field in field_vec_ngram2.iter() {
3089 let document_length_normalized = DOCUMENT_LENGTH_COMPRESSION[if index.meta.access_type
3090 == AccessType::Mmap
3091 {
3092 get_document_length_compressed_mmap(index, field.0 as usize, block_id, max_docid)
3093 } else {
3094 index.level_index[block_id].document_length_compressed_array[field.0 as usize]
3095 [max_docid]
3096 } as usize] as f32;
3097
3098 let document_length_quotient =
3099 document_length_normalized / index.document_length_normalized_average;
3100
3101 let tf_ngram2 = field.1 as f32;
3102
3103 let weight = index.indexed_schema_vec[field.0 as usize].boost;
3104
3105 bm25f += weight
3106 * idf_ngram2
3107 * ((tf_ngram2 * (K + 1.0)
3108 / (tf_ngram2 + (K * (1.0 - B + (B * document_length_quotient)))))
3109 + SIGMA);
3110 }
3111 } else {
3112 let idf_ngram1 = (((index.indexed_doc_count as f32 - posting_count_ngram_1 as f32 + 0.5)
3113 / (posting_count_ngram_1 as f32 + 0.5))
3114 + 1.0)
3115 .ln();
3116
3117 let idf_ngram2 = (((index.indexed_doc_count as f32 - posting_count_ngram_2 as f32 + 0.5)
3118 / (posting_count_ngram_2 as f32 + 0.5))
3119 + 1.0)
3120 .ln();
3121
3122 let idf_ngram3 = (((index.indexed_doc_count as f32 - posting_count_ngram_3 as f32 + 0.5)
3123 / (posting_count_ngram_3 as f32 + 0.5))
3124 + 1.0)
3125 .ln();
3126
3127 for field in field_vec_ngram1.iter() {
3128 let document_length_normalized = DOCUMENT_LENGTH_COMPRESSION[if index.meta.access_type
3129 == AccessType::Mmap
3130 {
3131 get_document_length_compressed_mmap(index, field.0 as usize, block_id, max_docid)
3132 } else {
3133 index.level_index[block_id].document_length_compressed_array[field.0 as usize]
3134 [max_docid]
3135 } as usize] as f32;
3136
3137 let document_length_quotient =
3138 document_length_normalized / index.document_length_normalized_average;
3139
3140 let tf_ngram1 = field.1 as f32;
3141
3142 let weight = index.indexed_schema_vec[field.0 as usize].boost;
3143
3144 bm25f += weight
3145 * idf_ngram1
3146 * ((tf_ngram1 * (K + 1.0)
3147 / (tf_ngram1 + (K * (1.0 - B + (B * document_length_quotient)))))
3148 + SIGMA);
3149 }
3150
3151 for field in field_vec_ngram2.iter() {
3152 let document_length_normalized = DOCUMENT_LENGTH_COMPRESSION[if index.meta.access_type
3153 == AccessType::Mmap
3154 {
3155 get_document_length_compressed_mmap(index, field.0 as usize, block_id, max_docid)
3156 } else {
3157 index.level_index[block_id].document_length_compressed_array[field.0 as usize]
3158 [max_docid]
3159 } as usize] as f32;
3160
3161 let document_length_quotient =
3162 document_length_normalized / index.document_length_normalized_average;
3163
3164 let tf_ngram2 = field.1 as f32;
3165
3166 let weight = index.indexed_schema_vec[field.0 as usize].boost;
3167
3168 bm25f += weight
3169 * idf_ngram2
3170 * ((tf_ngram2 * (K + 1.0)
3171 / (tf_ngram2 + (K * (1.0 - B + (B * document_length_quotient)))))
3172 + SIGMA);
3173 }
3174
3175 for field in field_vec_ngram3.iter() {
3176 let document_length_normalized = DOCUMENT_LENGTH_COMPRESSION[if index.meta.access_type
3177 == AccessType::Mmap
3178 {
3179 get_document_length_compressed_mmap(index, field.0 as usize, block_id, max_docid)
3180 } else {
3181 index.level_index[block_id].document_length_compressed_array[field.0 as usize]
3182 [max_docid]
3183 } as usize] as f32;
3184
3185 let document_length_quotient =
3186 document_length_normalized / index.document_length_normalized_average;
3187
3188 let tf_ngram3 = field.1 as f32;
3189
3190 let weight = index.indexed_schema_vec[field.0 as usize].boost;
3191
3192 bm25f += weight
3193 * idf_ngram3
3194 * ((tf_ngram3 * (K + 1.0)
3195 / (tf_ngram3 + (K * (1.0 - B + (B * document_length_quotient)))))
3196 + SIGMA);
3197 }
3198 }
3199 bm25f
3200}
3201
3202pub(crate) fn update_list_max_impact_score(index: &mut Shard) {
3203 if index.meta.access_type == AccessType::Mmap {
3204 return;
3205 }
3206
3207 for key0 in 0..index.segment_number1 {
3208 let keys: Vec<u64> = index.segments_index[key0].segment.keys().cloned().collect();
3209 for key in keys {
3210 let ngram_type = FromPrimitive::from_u64(key & 0b111).unwrap_or(NgramType::SingleTerm);
3211
3212 let blocks_len = index.segments_index[key0].segment[&key].blocks.len();
3213 let mut max_list_score = 0.0;
3214 for block_index in 0..blocks_len {
3215 let segment = &index.segments_index[key0];
3216 let posting_list = &segment.segment[&key];
3217 let block = &posting_list.blocks[block_index];
3218 let max_block_score = get_max_score(
3219 index,
3220 segment,
3221 posting_list.posting_count_ngram_1,
3222 posting_list.posting_count_ngram_2,
3223 posting_list.posting_count_ngram_3,
3224 posting_list.posting_count,
3225 block.block_id as usize,
3226 block.max_docid as usize,
3227 block.max_p_docid as usize,
3228 block.pointer_pivot_p_docid as usize,
3229 block.compression_type_pointer,
3230 &ngram_type,
3231 );
3232
3233 index.segments_index[key0]
3234 .segment
3235 .get_mut(&key)
3236 .unwrap()
3237 .blocks[block_index]
3238 .max_block_score = max_block_score;
3239 max_list_score = f32::max(max_list_score, max_block_score);
3240 }
3241 index.segments_index[key0]
3242 .segment
3243 .get_mut(&key)
3244 .unwrap()
3245 .max_list_score = max_list_score;
3246 }
3247 }
3248}
3249
3250pub(crate) async fn open_shard(
3254 index_path: &Path,
3255 mute: bool,
3256 vector_type: Precision,
3257 vector_dimensions: usize,
3258) -> Result<ShardArc, String> {
3259 if !mute {
3260 println!("opening index ...");
3261 }
3262
3263 let mut index_mmap_position = INDEX_HEADER_SIZE as usize;
3264 let mut docstore_mmap_position = 0;
3265
3266 let vector_size = size_of::<VectorHeader>()
3267 + (vector_dimensions
3268 * match vector_type {
3269 Precision::F32 => 4,
3270 Precision::I8 => 1,
3271 Precision::None => 0,
3272 });
3273
3274 match File::open(Path::new(index_path).join(META_FILENAME)) {
3275 Ok(meta_file) => {
3276 let meta: IndexMetaObject = serde_json::from_reader(BufReader::new(meta_file)).unwrap();
3277
3278 match File::open(Path::new(index_path).join(SCHEMA_FILENAME)) {
3279 Ok(schema_file) => {
3280 let schema = serde_json::from_reader(BufReader::new(schema_file)).unwrap();
3281
3282 let synonyms = if let Ok(synonym_file) =
3283 File::open(Path::new(index_path).join(SYNONYMS_FILENAME))
3284 {
3285 serde_json::from_reader(BufReader::new(synonym_file)).unwrap_or_default()
3286 } else {
3287 Vec::new()
3288 };
3289
3290 match create_shard(index_path, &meta, &schema, false, &synonyms, 11, mute, None)
3291 {
3292 Ok(mut shard) => {
3293 let mut block_count_sum = 0;
3294
3295 let is_mmap = shard.meta.access_type == AccessType::Mmap;
3296
3297 let file_len = if is_mmap {
3298 shard.index_file_mmap.len() as u64
3299 } else {
3300 shard.index_file.metadata().unwrap().len()
3301 };
3302
3303 while if is_mmap {
3304 index_mmap_position as u64
3305 } else {
3306 shard.index_file.stream_position().unwrap()
3307 } < file_len
3308 {
3309 let mut segment_head_vec: Vec<(u32, u32)> = Vec::new();
3310 for key0 in 0..shard.segment_number1 {
3311 if key0 == 0 {
3312 shard.last_level_index_file_start_pos = if is_mmap {
3313 index_mmap_position as u64
3314 } else {
3315 shard.index_file.stream_position().unwrap()
3316 };
3317
3318 shard.last_level_docstore_file_start_pos = if is_mmap {
3319 docstore_mmap_position as u64
3320 } else {
3321 shard.docstore_file.stream_position().unwrap()
3322 };
3323
3324 if shard.level_index.is_empty() {
3325 let longest_field_id = if is_mmap {
3326 read_u16_ref(
3327 &shard.index_file_mmap,
3328 &mut index_mmap_position,
3329 )
3330 as usize
3331 } else {
3332 let _ = shard.index_file.read(
3333 &mut shard
3334 .compressed_index_segment_block_buffer
3335 [0..2],
3336 );
3337 read_u16(
3338 &shard.compressed_index_segment_block_buffer,
3339 0,
3340 )
3341 as usize
3342 };
3343
3344 for indexed_field in shard.indexed_field_vec.iter_mut()
3345 {
3346 indexed_field.is_longest_field = indexed_field
3347 .indexed_field_id
3348 == longest_field_id;
3349
3350 if indexed_field.is_longest_field {
3351 shard.longest_field_id = longest_field_id
3352 }
3353 }
3354 }
3355
3356 let mut document_length_compressed_array_vec: Vec<
3357 [u8; ROARING_BLOCK_SIZE],
3358 > = Vec::new();
3359
3360 let document_length_compressed_array_pointer = if is_mmap {
3361 index_mmap_position
3362 } else {
3363 shard.index_file.stream_position().unwrap() as usize
3364 };
3365
3366 for _i in 0..shard.indexed_field_vec.len() {
3367 if is_mmap {
3368 index_mmap_position += ROARING_BLOCK_SIZE;
3369 } else {
3370 let mut document_length_compressed_array_item =
3371 [0u8; ROARING_BLOCK_SIZE];
3372
3373 let _ = shard.index_file.read(
3374 &mut document_length_compressed_array_item,
3375 );
3376 document_length_compressed_array_vec
3377 .push(document_length_compressed_array_item);
3378 }
3379 }
3380
3381 let mut docstore_pointer_docs: Vec<u8> = Vec::new();
3382
3383 let mut docstore_pointer_docs_pointer = 0;
3384 if !shard.stored_field_names.is_empty() {
3385 if is_mmap {
3386 let docstore_pointer_docs_size = read_u32_ref(
3387 &shard.docstore_file_mmap,
3388 &mut docstore_mmap_position,
3389 )
3390 as usize;
3391 docstore_pointer_docs_pointer =
3392 docstore_mmap_position;
3393 docstore_mmap_position +=
3394 docstore_pointer_docs_size;
3395 } else {
3396 let _ = shard.docstore_file.read(
3397 &mut shard
3398 .compressed_index_segment_block_buffer
3399 [0..4],
3400 );
3401
3402 let docstore_pointer_docs_size = read_u32(
3403 &shard.compressed_index_segment_block_buffer,
3404 0,
3405 )
3406 as usize;
3407
3408 docstore_pointer_docs_pointer =
3409 shard.docstore_file.stream_position().unwrap()
3410 as usize;
3411 docstore_pointer_docs =
3412 vec![0; docstore_pointer_docs_size];
3413 let _ = shard
3414 .docstore_file
3415 .read(&mut docstore_pointer_docs);
3416 }
3417 }
3418
3419 if is_mmap {
3420 let _previous_indexed_doc_count =
3421 shard.indexed_doc_count;
3422 shard.indexed_doc_count = read_u64_ref(
3423 &shard.index_file_mmap,
3424 &mut index_mmap_position,
3425 )
3426 as usize;
3427 shard.positions_sum_normalized = read_u64_ref(
3428 &shard.index_file_mmap,
3429 &mut index_mmap_position,
3430 );
3431
3432 for _key0 in 0..shard.segment_number1 {
3433 let block_length = read_u32_ref(
3434 &shard.index_file_mmap,
3435 &mut index_mmap_position,
3436 );
3437 let key_count = read_u32_ref(
3438 &shard.index_file_mmap,
3439 &mut index_mmap_position,
3440 );
3441
3442 segment_head_vec.push((block_length, key_count));
3443 }
3444 } else {
3445 let _ = shard.index_file.read(
3446 &mut shard.compressed_index_segment_block_buffer
3447 [0..16],
3448 );
3449
3450 shard.indexed_doc_count = read_u64(
3451 &shard.compressed_index_segment_block_buffer,
3452 0,
3453 )
3454 as usize;
3455
3456 shard.positions_sum_normalized = read_u64(
3457 &shard.compressed_index_segment_block_buffer,
3458 8,
3459 );
3460
3461 for _key0 in 0..shard.segment_number1 {
3462 let _ = shard.index_file.read(
3463 &mut shard
3464 .compressed_index_segment_block_buffer
3465 [0..8],
3466 );
3467
3468 let block_length = read_u32(
3469 &shard.compressed_index_segment_block_buffer,
3470 0,
3471 );
3472 let key_count = read_u32(
3473 &shard.compressed_index_segment_block_buffer,
3474 4,
3475 );
3476 segment_head_vec.push((block_length, key_count));
3477 }
3478 }
3479
3480 shard.document_length_normalized_average =
3481 shard.positions_sum_normalized as f32
3482 / shard.indexed_doc_count as f32;
3483
3484 shard.level_index.push(LevelIndex {
3485 document_length_compressed_array:
3486 document_length_compressed_array_vec,
3487 docstore_pointer_docs,
3488 docstore_pointer_docs_pointer,
3489 document_length_compressed_array_pointer,
3490 });
3491 }
3492
3493 let block_length = segment_head_vec[key0].0;
3494 let key_count = segment_head_vec[key0].1;
3495
3496 let block_id =
3497 (block_count_sum >> shard.segment_number_bits1) as u32;
3498 block_count_sum += 1;
3499
3500 let key_body_pointer_write_start: u32 =
3501 key_count * shard.key_head_size as u32;
3502
3503 if is_mmap {
3504 index_mmap_position +=
3505 key_count as usize * shard.key_head_size;
3506 shard.segments_index[key0].byte_array_blocks_pointer.push(
3507 (
3508 index_mmap_position,
3509 (block_length - key_body_pointer_write_start)
3510 as usize,
3511 key_count,
3512 ),
3513 );
3514
3515 index_mmap_position +=
3516 (block_length - key_body_pointer_write_start) as usize;
3517 } else {
3518 let _ = shard.index_file.read(
3519 &mut shard.compressed_index_segment_block_buffer
3520 [0..(key_count as usize * shard.key_head_size)],
3521 );
3522 let compressed_index_segment_block_buffer = &shard
3523 .compressed_index_segment_block_buffer
3524 [0..(key_count as usize * shard.key_head_size)];
3525
3526 let mut block_array: Vec<u8> = vec![
3527 0;
3528 (block_length - key_body_pointer_write_start)
3529 as usize
3530 ];
3531
3532 let _ = shard.index_file.read(&mut block_array);
3533 shard.segments_index[key0]
3534 .byte_array_blocks
3535 .push(block_array);
3536
3537 let mut read_pointer = 0;
3538
3539 let mut posting_count_previous = 0;
3540 let mut pointer_pivot_p_docid_previous = 0;
3541 let mut compression_type_pointer_previous = 0;
3542
3543 for key_index in 0..key_count {
3544 let key_hash = read_u64_ref(
3545 compressed_index_segment_block_buffer,
3546 &mut read_pointer,
3547 );
3548
3549 let posting_count = read_u16_ref(
3550 compressed_index_segment_block_buffer,
3551 &mut read_pointer,
3552 );
3553
3554 let max_docid = read_u16_ref(
3555 compressed_index_segment_block_buffer,
3556 &mut read_pointer,
3557 );
3558
3559 let max_p_docid = read_u16_ref(
3560 compressed_index_segment_block_buffer,
3561 &mut read_pointer,
3562 );
3563
3564 let mut posting_count_ngram_1 = 0;
3565 let mut posting_count_ngram_2 = 0;
3566 let mut posting_count_ngram_3 = 0;
3567 match shard.key_head_size {
3568 20 => {}
3569 22 => {
3570 let posting_count_ngram_1_compressed =
3571 read_u8_ref(
3572 compressed_index_segment_block_buffer,
3573 &mut read_pointer,
3574 );
3575 posting_count_ngram_1 =
3576 DOCUMENT_LENGTH_COMPRESSION
3577 [posting_count_ngram_1_compressed
3578 as usize];
3579
3580 let posting_count_ngram_2_compressed =
3581 read_u8_ref(
3582 compressed_index_segment_block_buffer,
3583 &mut read_pointer,
3584 );
3585 posting_count_ngram_2 =
3586 DOCUMENT_LENGTH_COMPRESSION
3587 [posting_count_ngram_2_compressed
3588 as usize];
3589 }
3590 _ => {
3591 let posting_count_ngram_1_compressed =
3592 read_u8_ref(
3593 compressed_index_segment_block_buffer,
3594 &mut read_pointer,
3595 );
3596 posting_count_ngram_1 =
3597 DOCUMENT_LENGTH_COMPRESSION
3598 [posting_count_ngram_1_compressed
3599 as usize];
3600
3601 let posting_count_ngram_2_compressed =
3602 read_u8_ref(
3603 compressed_index_segment_block_buffer,
3604 &mut read_pointer,
3605 );
3606 posting_count_ngram_2 =
3607 DOCUMENT_LENGTH_COMPRESSION
3608 [posting_count_ngram_2_compressed
3609 as usize];
3610
3611 let posting_count_ngram_3_compressed =
3612 read_u8_ref(
3613 compressed_index_segment_block_buffer,
3614 &mut read_pointer,
3615 );
3616 posting_count_ngram_3 =
3617 DOCUMENT_LENGTH_COMPRESSION
3618 [posting_count_ngram_3_compressed
3619 as usize];
3620 }
3621 }
3622
3623 let pointer_pivot_p_docid = read_u16_ref(
3624 compressed_index_segment_block_buffer,
3625 &mut read_pointer,
3626 );
3627
3628 let compression_type_pointer = read_u32_ref(
3629 compressed_index_segment_block_buffer,
3630 &mut read_pointer,
3631 );
3632
3633 if let Some(value) = shard.segments_index[key0]
3634 .segment
3635 .get_mut(&key_hash)
3636 {
3637 value.posting_count += posting_count as u32 + 1;
3638
3639 value.blocks.push(BlockObjectIndex {
3640 max_block_score: 0.0,
3641 block_id,
3642 posting_count,
3643 max_docid,
3644 max_p_docid,
3645 pointer_pivot_p_docid,
3646 compression_type_pointer,
3647 });
3648 } else {
3649 let value = PostingListObjectIndex {
3650 posting_count: posting_count as u32 + 1,
3651 posting_count_ngram_1,
3652 posting_count_ngram_2,
3653 posting_count_ngram_3,
3654 max_list_score: 0.0,
3655 position_range_previous: 0,
3656 blocks: vec![BlockObjectIndex {
3657 max_block_score: 0.0,
3658 block_id,
3659 posting_count,
3660 max_docid,
3661 max_p_docid,
3662 pointer_pivot_p_docid,
3663 compression_type_pointer,
3664 }],
3665 ..Default::default()
3666 };
3667 shard.segments_index[key0]
3668 .segment
3669 .insert(key_hash, value);
3670 };
3671
3672 if !shard
3673 .indexed_doc_count
3674 .is_multiple_of(ROARING_BLOCK_SIZE)
3675 && block_id as usize
3676 == shard.indexed_doc_count / ROARING_BLOCK_SIZE
3677 && shard.meta.access_type == AccessType::Ram
3678 {
3679 let position_range_previous = if key_index == 0 {
3680 0
3681 } else {
3682 let posting_pointer_size_sum_previous =
3683 pointer_pivot_p_docid_previous as usize * 2
3684 + if (pointer_pivot_p_docid_previous
3685 as usize)
3686 < posting_count_previous
3687 {
3688 (posting_count_previous
3689 - pointer_pivot_p_docid_previous
3690 as usize)
3691 * 3
3692 } else {
3693 0
3694 };
3695
3696 let rank_position_pointer_range_previous= compression_type_pointer_previous & 0b0011_1111_1111_1111_1111_1111_1111_1111;
3697 let compression_type_previous: CompressionType =
3698 FromPrimitive::from_u32(
3699 compression_type_pointer_previous >> 30,
3700 )
3701 .unwrap();
3702
3703 let compressed_docid_previous =
3704 match compression_type_previous {
3705 CompressionType::Array => {
3706 posting_count_previous * 2
3707 }
3708 CompressionType::Bitmap => 8192,
3709 CompressionType::Rle => {
3710 let byte_array_docid = &shard
3711 .segments_index[key0]
3712 .byte_array_blocks
3713 [block_id as usize];
3714 4 * read_u16( byte_array_docid, rank_position_pointer_range_previous as usize +posting_pointer_size_sum_previous) as usize + 2
3715 }
3716 _ => 0,
3717 };
3718
3719 rank_position_pointer_range_previous
3720 + (posting_pointer_size_sum_previous
3721 + compressed_docid_previous)
3722 as u32
3723 };
3724
3725 let plo = shard.segments_index[key0]
3726 .segment
3727 .get_mut(&key_hash)
3728 .unwrap();
3729
3730 plo.position_range_previous =
3731 position_range_previous;
3732
3733 posting_count_previous = posting_count as usize + 1;
3734 pointer_pivot_p_docid_previous =
3735 pointer_pivot_p_docid;
3736 compression_type_pointer_previous =
3737 compression_type_pointer;
3738 };
3739 }
3740 }
3741 }
3742 }
3743
3744 shard.committed_doc_count = shard.indexed_doc_count;
3745 shard.is_last_level_incomplete =
3746 !shard.committed_doc_count.is_multiple_of(ROARING_BLOCK_SIZE);
3747
3748 if shard.is_vector_indexing && !shard.vector_file_mmap.is_empty() {
3749 shard.indexed_vector_count = 0;
3750
3751 let mut offset = 0;
3752 for _level_id in 0..shard.level_index.len() {
3753 shard.last_level_vector_file_start_pos = offset as u64;
3754
3755 let cluster_number_bytes =
3756 &shard.vector_file_mmap[offset..offset + 4];
3757 let cluster_number = u32::from_le_bytes(
3758 cluster_number_bytes.try_into().unwrap(),
3759 )
3760 as usize;
3761 offset += 4;
3762
3763 let mut level_vectors_count = 0;
3764 let mut start_index = 0;
3765 for _i in 0..cluster_number {
3766 let cluster_header_bytes =
3767 &shard.vector_file_mmap[offset..offset + 4];
3768 let cluster_header = ClusterHeader {
3769 start_index,
3770 child_count: u32::from_le_bytes(
3771 cluster_header_bytes.try_into().unwrap(),
3772 ),
3773 };
3774 offset += 4;
3775 start_index += cluster_header.child_count;
3776 level_vectors_count += cluster_header.child_count;
3777 }
3778
3779 shard.indexed_vector_count += level_vectors_count as usize;
3780 shard.indexed_cluster_count += cluster_number;
3781
3782 offset += level_vectors_count as usize * vector_size;
3783 }
3784 }
3785
3786 for (i, component) in shard.bm25_component_cache.iter_mut().enumerate()
3787 {
3788 let document_length_quotient = DOCUMENT_LENGTH_COMPRESSION[i]
3789 as f32
3790 / shard.document_length_normalized_average;
3791 *component = K * (1.0 - B + B * document_length_quotient);
3792 }
3793
3794 shard.string_set_to_single_term_id();
3795
3796 update_list_max_impact_score(&mut shard);
3797
3798 let mut reader = BufReader::with_capacity(8192, &shard.delete_file);
3799 while let Ok(buffer) = reader.fill_buf() {
3800 let length = buffer.len();
3801
3802 if length == 0 {
3803 break;
3804 }
3805
3806 for i in (0..length).step_by(8) {
3807 let docid = read_u64(buffer, i);
3808 shard.delete_hashset.insert(docid as usize);
3809 }
3810
3811 reader.consume(length);
3812 }
3813
3814 let shard_arc = Arc::new(RwLock::new(shard));
3815
3816 warmup(&shard_arc).await;
3817 Ok(shard_arc.clone())
3818 }
3819 Err(err) => Err(err.to_string()),
3820 }
3821 }
3822 Err(err) => Err(err.to_string()),
3823 }
3824 }
3825 Err(err) => Err(err.to_string()),
3826 }
3827}
3828
3829pub async fn open_index(index_path: &Path) -> Result<IndexArc, String> {
3833 let start_time = Instant::now();
3834
3835 match File::open(Path::new(index_path).join(META_FILENAME)) {
3836 Ok(meta_file) => {
3837 let meta: IndexMetaObject = serde_json::from_reader(BufReader::new(meta_file)).unwrap();
3838
3839 match File::open(Path::new(index_path).join(SCHEMA_FILENAME)) {
3840 Ok(schema_file) => {
3841 let schema = serde_json::from_reader(BufReader::new(schema_file)).unwrap();
3842
3843 let synonyms = if let Ok(synonym_file) =
3844 File::open(Path::new(index_path).join(SYNONYMS_FILENAME))
3845 {
3846 serde_json::from_reader(BufReader::new(synonym_file)).unwrap_or_default()
3847 } else {
3848 Vec::new()
3849 };
3850
3851 let shard_number = index_path
3852 .join("shards")
3853 .read_dir()
3854 .unwrap()
3855 .filter_map(Result::ok)
3856 .filter(|entry| entry.path().is_dir())
3857 .filter_map(|entry| entry.file_name().into_string().ok())
3858 .filter(|name| name.parse::<usize>().is_ok())
3859 .count();
3860
3861 match create_index_root(
3862 index_path,
3863 meta,
3864 &schema,
3865 false,
3866 &synonyms,
3867 11,
3868 false,
3869 Some(shard_number),
3870 )
3871 .await
3872 {
3873 Ok(index_arc) => {
3874 let lock = Arc::into_inner(index_arc).unwrap();
3875 let index = RwLock::into_inner(lock);
3876
3877 let index_arc = Arc::new(RwLock::new(index));
3878
3879 if let Some(symspell) =
3880 &mut index_arc.read().await.symspell_option.as_ref()
3881 {
3882 let dictionary_path =
3883 Path::new(&index_arc.read().await.index_path_string)
3884 .join(DICTIONARY_FILENAME);
3885 let _ = symspell.write().await.load_dictionary(
3886 &dictionary_path,
3887 0,
3888 1,
3889 " ",
3890 );
3891 }
3892
3893 if let Some(completion_option) =
3894 &mut index_arc.read().await.completion_option.as_ref()
3895 {
3896 let _ = completion_option.write().await.load_completions(
3897 &Path::new(&index_arc.read().await.index_path_string)
3898 .join(COMPLETIONS_FILENAME),
3899 0,
3900 1,
3901 ":",
3902 );
3903 }
3904
3905 let mut shard_vec: Vec<Arc<RwLock<Shard>>> = Vec::new();
3906
3907 let vector_type = match index_arc.read().await.quantization {
3908 Quantization::ScalarQuantizationI8 => Precision::I8,
3909 Quantization::TurboQuantI8 => Precision::I8,
3910 _ => index_arc.read().await.vector_precision,
3911 };
3912
3913 let dimensions = index_arc.read().await.vector_dimensions;
3914
3915 let paths: Vec<_> = fs::read_dir(index_path.join("shards"))
3916 .unwrap()
3917 .filter_map(Result::ok)
3918 .collect();
3919 let mut shard_handle_vec = Vec::new();
3920 let index_path_clone = Arc::new(index_path.to_path_buf());
3921 for i in 0..paths.len() {
3922 let index_path_clone2 = index_path_clone.clone();
3923 let vector_type_clone = vector_type;
3924 let dimensions_clone = dimensions;
3925 shard_handle_vec.push(tokio::spawn(async move {
3926 let path = index_path_clone2.join("shards").join(i.to_string());
3927 open_shard(&path, true, vector_type_clone, dimensions_clone)
3928 .await
3929 .unwrap()
3930 }));
3931 }
3932
3933 for shard_handle in shard_handle_vec {
3934 let shard_arc = shard_handle.await.unwrap();
3935 shard_arc.write().await.index_option = Some(index_arc.clone());
3936
3937 shard_arc.write().await.quantization =
3938 index_arc.read().await.quantization;
3939 shard_arc.write().await.shard_number =
3940 index_arc.read().await.shard_number;
3941 shard_arc.write().await.vector_dimensions =
3942 index_arc.read().await.vector_dimensions;
3943 shard_arc.write().await.vector_dimensions_original =
3944 index_arc.read().await.vector_dimensions_original;
3945 shard_arc.write().await.vector_precision =
3946 index_arc.read().await.vector_precision;
3947 shard_arc.write().await.vector_similarity =
3948 index_arc.read().await.vector_similarity;
3949 shard_arc.write().await.is_avx2 = index_arc.read().await.is_avx2;
3950 shard_arc.write().await.is_neon = index_arc.read().await.is_neon;
3951 shard_arc.write().await.is_simd = index_arc.read().await.is_simd;
3952 shard_arc.write().await.chunk_size =
3953 index_arc.read().await.chunk_size;
3954
3955 shard_arc.write().await.turbo_quant =
3956 index_arc.read().await.turbo_quant.clone();
3957
3958 if shard_arc.read().await.is_vector_indexing
3959 && !shard_arc.read().await.vector_file_mmap.is_empty()
3960 && shard_arc.read().await.quantization
3961 == Quantization::ScalarQuantizationI8
3962 && shard_arc.read().await.vector_similarity
3963 == VectorSimilarity::Euclidean
3964 {
3965 let (min_vector_value, max_vector_value) = read_min_max(
3966 &shard_arc.read().await.vector_file_mmap,
3967 shard_arc.read().await.vector_dimensions,
3968 );
3969 shard_arc.write().await.min_vector_value = min_vector_value;
3970 shard_arc.write().await.max_vector_value = max_vector_value;
3971 }
3972
3973 index_arc.write().await.indexed_doc_count +=
3974 shard_arc.read().await.indexed_doc_count;
3975 index_arc.write().await.indexed_vector_count +=
3976 shard_arc.read().await.indexed_vector_count;
3977 index_arc.write().await.indexed_cluster_count +=
3978 shard_arc.read().await.indexed_cluster_count;
3979 index_arc.write().await.deleted_doc_count +=
3980 shard_arc.read().await.delete_hashset.len();
3981 let _shard_id = shard_arc.read().await.meta.id;
3982 shard_vec.push(shard_arc);
3983 }
3984
3985 let indexed_doc_count = index_arc.read().await.indexed_doc_count;
3986 *index_arc.write().await.docid_global.write().await = indexed_doc_count;
3987
3988 index_arc.write().await.shard_number = shard_vec.len();
3989
3990 index_arc.write().await.shard_vec = shard_vec;
3991
3992 let _elapsed_time = start_time.elapsed().as_nanos();
3993
3994 Ok(index_arc.clone())
3995 }
3996 Err(err) => Err(err.to_string()),
3997 }
3998 }
3999 Err(err) => Err(err.to_string()),
4000 }
4001 }
4002 Err(err) => Err(err.to_string()),
4003 }
4004}
4005
4006pub(crate) async fn warmup(shard_object_arc: &ShardArc) {
4007 shard_object_arc.write().await.frequentword_results.clear();
4008 let mut query_facets: Vec<QueryFacet> = Vec::new();
4009 for facet in shard_object_arc.read().await.facets.iter() {
4010 match facet.field_type {
4011 FieldType::String16 => query_facets.push(QueryFacet::String16 {
4012 field: facet.name.clone(),
4013 prefix: "".into(),
4014 length: u16::MAX,
4015 }),
4016 FieldType::String32 => query_facets.push(QueryFacet::String32 {
4017 field: facet.name.clone(),
4018 prefix: "".into(),
4019 length: u32::MAX,
4020 }),
4021 FieldType::StringSet16 => query_facets.push(QueryFacet::StringSet16 {
4022 field: facet.name.clone(),
4023 prefix: "".into(),
4024 length: u16::MAX,
4025 }),
4026 FieldType::StringSet32 => query_facets.push(QueryFacet::StringSet32 {
4027 field: facet.name.clone(),
4028 prefix: "".into(),
4029 length: u32::MAX,
4030 }),
4031 _ => {}
4032 }
4033 }
4034
4035 let frequent_words = shard_object_arc.read().await.frequent_words.clone();
4036 for frequentword in frequent_words.iter() {
4037 let results_list = shard_object_arc
4038 .search_lexical_shard(
4039 frequentword.to_owned(),
4040 QueryType::Union,
4041 false,
4042 0,
4043 1000,
4044 ResultType::TopkCount,
4045 false,
4046 Vec::new(),
4047 query_facets.clone(),
4048 Vec::new(),
4049 Vec::new(),
4050 )
4051 .await;
4052
4053 let mut index_mut = shard_object_arc.write().await;
4054 index_mut
4055 .frequentword_results
4056 .insert(frequentword.to_string(), results_list);
4057 }
4058}
4059
4060#[derive(Default, Debug, Deserialize, Serialize, Clone)]
4061pub(crate) struct TermObject {
4062 pub key_hash: u64,
4063 pub key0: u32,
4064 pub term: String,
4065
4066 pub ngram_type: NgramType,
4067
4068 pub term_ngram_2: String,
4069 pub term_ngram_1: String,
4070 pub term_ngram_0: String,
4071 pub field_vec_ngram1: Vec<(usize, u32)>,
4072 pub field_vec_ngram2: Vec<(usize, u32)>,
4073 pub field_vec_ngram3: Vec<(usize, u32)>,
4074
4075 pub field_positions_vec: Vec<Vec<u16>>,
4076}
4077
4078#[derive(Default, Debug, Serialize, Deserialize, Clone)]
4079pub(crate) struct NonUniqueTermObject {
4080 pub term: String,
4081 pub ngram_type: NgramType,
4082
4083 pub term_ngram_2: String,
4084 pub term_ngram_1: String,
4085 pub term_ngram_0: String,
4086 pub op: QueryType,
4087}
4088
4089pub static IS_SYSTEM_LE: LazyLock<bool> = LazyLock::new(|| u16::from_ne_bytes([1, 0]) == 1);
4091
4092pub static IS_AVX2: LazyLock<bool> = LazyLock::new(|| {
4094 #[cfg(target_arch = "x86_64")]
4095 let is_avx2 = is_x86_feature_detected!("avx2");
4096 #[cfg(not(target_arch = "x86_64"))]
4097 let is_avx2 = false;
4098 is_avx2
4099});
4100
4101pub static IS_NEON: LazyLock<bool> = LazyLock::new(|| {
4105 #[cfg(target_arch = "aarch64")]
4106 let is_neon = std::arch::is_aarch64_feature_detected!("neon");
4107 #[cfg(not(target_arch = "aarch64"))]
4108 let is_neon = false;
4109 is_neon
4110});
4111
4112pub static IS_SIMD: LazyLock<bool> = LazyLock::new(|| *IS_AVX2 || *IS_NEON);
4115
4116#[cfg(not(any(
4117 all(
4118 feature = "gxhash",
4119 target_arch = "x86_64",
4120 target_feature = "aes",
4121 target_feature = "sse2"
4122 ),
4123 all(
4124 feature = "gxhash",
4125 target_arch = "aarch64",
4126 target_feature = "aes",
4127 target_feature = "neon"
4128 )
4129)))]
4130pub(crate) static HASHER_32: LazyLock<RandomState> =
4131 LazyLock::new(|| RandomState::with_seeds(805272099, 242851902, 646123436, 591410655));
4132
4133#[cfg(not(any(
4134 all(
4135 feature = "gxhash",
4136 target_arch = "x86_64",
4137 target_feature = "aes",
4138 target_feature = "sse2"
4139 ),
4140 all(
4141 feature = "gxhash",
4142 target_arch = "aarch64",
4143 target_feature = "aes",
4144 target_feature = "neon"
4145 )
4146)))]
4147pub(crate) static HASHER_64: LazyLock<RandomState> =
4148 LazyLock::new(|| RandomState::with_seeds(808259318, 750368348, 84901999, 789810389));
4149
4150#[inline]
4151#[cfg(any(
4152 all(
4153 feature = "gxhash",
4154 target_arch = "x86_64",
4155 target_feature = "aes",
4156 target_feature = "sse2"
4157 ),
4158 all(
4159 feature = "gxhash",
4160 target_arch = "aarch64",
4161 target_feature = "aes",
4162 target_feature = "neon"
4163 )
4164))]
4165pub(crate) fn hash32(term_bytes: &[u8]) -> u32 {
4166 gxhash32(term_bytes, 1234)
4167}
4168
4169#[inline]
4170#[cfg(any(
4171 all(
4172 feature = "gxhash",
4173 target_arch = "x86_64",
4174 target_feature = "aes",
4175 target_feature = "sse2"
4176 ),
4177 all(
4178 feature = "gxhash",
4179 target_arch = "aarch64",
4180 target_feature = "aes",
4181 target_feature = "neon"
4182 )
4183))]
4184pub(crate) fn hash64(term_bytes: &[u8]) -> u64 {
4185 gxhash64(term_bytes, 1234) & 0b1111111111111111111111111111111111111111111111111111111111111000
4186}
4187
4188#[inline]
4189#[cfg(not(any(
4190 all(
4191 feature = "gxhash",
4192 target_arch = "x86_64",
4193 target_feature = "aes",
4194 target_feature = "sse2"
4195 ),
4196 all(
4197 feature = "gxhash",
4198 target_arch = "aarch64",
4199 target_feature = "aes",
4200 target_feature = "neon"
4201 )
4202)))]
4203pub(crate) fn hash32(term_bytes: &[u8]) -> u32 {
4204 HASHER_32.hash_one(term_bytes) as u32
4205}
4206
4207#[inline]
4208#[cfg(not(any(
4209 all(
4210 feature = "gxhash",
4211 target_arch = "x86_64",
4212 target_feature = "aes",
4213 target_feature = "sse2"
4214 ),
4215 all(
4216 feature = "gxhash",
4217 target_arch = "aarch64",
4218 target_feature = "aes",
4219 target_feature = "neon"
4220 )
4221)))]
4222pub(crate) fn hash64(term_bytes: &[u8]) -> u64 {
4223 HASHER_64.hash_one(term_bytes)
4224 & 0b1111111111111111111111111111111111111111111111111111111111111000
4225}
4226
4227static FREQUENT_EN: &str = include_str!("../assets/dictionaries/frequent_en.txt");
4228static FREQUENT_DE: &str = include_str!("../assets/dictionaries/frequent_de.txt");
4229static FREQUENT_FR: &str = include_str!("../assets/dictionaries/frequent_fr.txt");
4230static FREQUENT_ES: &str = include_str!("../assets/dictionaries/frequent_es.txt");
4231
4232pub(crate) const NUM_FREE_VALUES: u32 = 24;
4233
4234pub(crate) fn int_to_byte4(i: u32) -> u8 {
4238 if i < NUM_FREE_VALUES {
4239 i as u8
4240 } else {
4241 let ii = i - NUM_FREE_VALUES;
4242 let num_bits = 32 - ii.leading_zeros();
4243 if num_bits < 4 {
4244 (NUM_FREE_VALUES + ii) as u8
4245 } else {
4246 let shift = num_bits - 4;
4247 (NUM_FREE_VALUES + (((ii >> shift) & 0x07) | (shift + 1) << 3)) as u8
4248 }
4249 }
4250}
4251
4252pub(crate) const fn byte4_to_int(b: u8) -> u32 {
4256 if (b as u32) < NUM_FREE_VALUES {
4257 b as u32
4258 } else {
4259 let i = b as u32 - NUM_FREE_VALUES;
4260 let bits = i & 0x07;
4261 let shift = i >> 3;
4262 if shift == 0 {
4263 NUM_FREE_VALUES + bits
4264 } else {
4265 NUM_FREE_VALUES + ((bits | 0x08) << (shift - 1))
4266 }
4267 }
4268}
4269
4270pub(crate) const DOCUMENT_LENGTH_COMPRESSION: [u32; 256] = {
4272 let mut k2 = [0; 256];
4273 let mut i = 0usize;
4274 while i < 256 {
4275 k2[i] = byte4_to_int(i as u8);
4276 i += 1;
4277 }
4278 k2
4279};
4280
4281impl Shard {
4282 pub(crate) fn string_set_to_single_term_id(&mut self) {
4283 for (i, facet) in self.facets.iter().enumerate() {
4284 if facet.field_type == FieldType::StringSet16
4285 || facet.field_type == FieldType::StringSet32
4286 {
4287 for (idx, value) in facet.values.iter().enumerate() {
4288 for term in value.1.0.iter() {
4289 self.string_set_to_single_term_id_vec[i]
4290 .entry(term.to_string())
4291 .or_insert(AHashSet::from_iter(vec![idx as u32]))
4292 .insert(idx as u32);
4293 }
4294 }
4295 }
4296 }
4297 }
4298
4299 async fn clear_shard(&mut self) {
4301 let semaphore = self.semaphore.clone();
4302 let permit = semaphore.acquire_owned().await.unwrap();
4303
4304 self.level_terms.clear();
4305
4306 let mut mmap_options = MmapOptions::new();
4307 let mmap: MmapMut = mmap_options.len(4).map_anon().unwrap();
4308 self.index_file_mmap = mmap
4309 .make_read_only()
4310 .expect("Unable to make Mmap read-only");
4311
4312 let _ = self.index_file.rewind();
4313 if let Err(e) = self.index_file.set_len(0) {
4314 println!(
4315 "Unable to index_file.set_len in clear_index {} {} {:?}",
4316 self.index_path_string, self.indexed_doc_count, e
4317 )
4318 };
4319
4320 if !self.compressed_docstore_segment_block_buffer.is_empty() {
4321 self.compressed_docstore_segment_block_buffer = vec![0; ROARING_BLOCK_SIZE * 4];
4322 };
4323
4324 write_u16(
4325 INDEX_FORMAT_VERSION_MAJOR,
4326 &mut self.compressed_index_segment_block_buffer,
4327 0,
4328 );
4329 write_u16(
4330 INDEX_FORMAT_VERSION_MINOR,
4331 &mut self.compressed_index_segment_block_buffer,
4332 2,
4333 );
4334
4335 let _ = self
4336 .index_file
4337 .write(&self.compressed_index_segment_block_buffer[0..INDEX_HEADER_SIZE as usize]);
4338 let _ = self.index_file.flush();
4339
4340 self.index_file_mmap =
4341 unsafe { Mmap::map(&self.index_file).expect("Unable to create Mmap") };
4342
4343 self.docstore_file_mmap = unsafe {
4344 MmapOptions::new()
4345 .len(0)
4346 .map(&self.docstore_file)
4347 .expect("Unable to create Mmap")
4348 };
4349
4350 let _ = self.docstore_file.rewind();
4351 if let Err(e) = self.docstore_file.set_len(0) {
4352 println!("Unable to docstore_file.set_len in clear_index {:?}", e)
4353 };
4354 let _ = self.docstore_file.flush();
4355
4356 let _ = self.delete_file.rewind();
4357 if let Err(e) = self.delete_file.set_len(0) {
4358 println!("Unable to delete_file.set_len in clear_index {:?}", e)
4359 };
4360 let _ = self.delete_file.flush();
4361 self.delete_hashset.clear();
4362
4363 self.facets_file_mmap = unsafe {
4364 MmapOptions::new()
4365 .len(0)
4366 .map_mut(&self.facets_file)
4367 .expect("Unable to create Mmap")
4368 };
4369 let _ = self.facets_file.rewind();
4370 if let Err(e) = self
4371 .facets_file
4372 .set_len((self.facets_size_sum * ROARING_BLOCK_SIZE) as u64)
4373 {
4374 println!("Unable to facets_file.set_len in clear_index {:?}", e)
4375 };
4376 let _ = self.facets_file.flush();
4377
4378 self.facets_file_mmap =
4379 unsafe { MmapMut::map_mut(&self.facets_file).expect("Unable to create Mmap") };
4380 let index_path = Path::new(&self.index_path_string);
4381 let _ = fs::remove_file(index_path.join(FACET_VALUES_FILENAME));
4382 for facet in self.facets.iter_mut() {
4383 facet.values.clear();
4384 facet.min = ValueType::None;
4385 facet.max = ValueType::None;
4386 }
4387
4388 if !self.stored_field_names.is_empty() && self.meta.access_type == AccessType::Mmap {
4389 self.docstore_file_mmap =
4390 unsafe { Mmap::map(&self.docstore_file).expect("Unable to create Mmap") };
4391 }
4392
4393 self.vector_file_mmap = unsafe {
4394 MmapOptions::new()
4395 .len(0)
4396 .map(&self.docstore_file)
4397 .expect("Unable to create Mmap")
4398 };
4399 let _ = self.vector_file.rewind();
4400 if let Err(e) = self.vector_file.set_len(0) {
4401 println!("Unable to vector_file.set_len in clear_index {:?}", e)
4402 };
4403 let _ = self.vector_file.flush();
4404 self.vector_file_mmap =
4405 unsafe { Mmap::map(&self.vector_file).expect("Unable to create Mmap") };
4406 self.indexed_vector_count = 0;
4407 self.indexed_cluster_count = 0;
4408
4409 self.document_length_normalized_average = 0.0;
4410 self.indexed_doc_count = 0;
4411 self.committed_doc_count = 0;
4412 self.positions_sum_normalized = 0;
4413
4414 self.level_index = Vec::new();
4415
4416 for segment in self.segments_index.iter_mut() {
4417 segment.byte_array_blocks.clear();
4418 segment.byte_array_blocks_pointer.clear();
4419 segment.segment.clear();
4420 }
4421
4422 for segment in self.segments_level0.iter_mut() {
4423 segment.segment.clear();
4424 }
4425
4426 self.key_count_sum = 0;
4427 self.block_id = 0;
4428 self.strip_compressed_sum = 0;
4429 self.postings_buffer_pointer = 0;
4430 self.docid_count = 0;
4431 self.size_compressed_docid_index = 0;
4432 self.size_compressed_positions_index = 0;
4433 self.position_count = 0;
4434 self.postinglist_count = 0;
4435
4436 self.is_last_level_incomplete = false;
4437
4438 drop(permit);
4439 }
4440
4441 pub(crate) fn get_index_string_facets_shard(
4442 &self,
4443 query_facets: Vec<QueryFacet>,
4444 ) -> Option<AHashMap<String, Facet>> {
4445 if self.facets.is_empty() {
4446 return None;
4447 }
4448
4449 let mut result_query_facets = Vec::new();
4450 if !query_facets.is_empty() {
4451 result_query_facets = vec![ResultFacet::default(); self.facets.len()];
4452 for query_facet in query_facets.iter() {
4453 match &query_facet {
4454 QueryFacet::String16 {
4455 field,
4456 prefix,
4457 length,
4458 } => {
4459 if let Some(idx) = self.facets_map.get(field)
4460 && self.facets[*idx].field_type == FieldType::String16
4461 {
4462 result_query_facets[*idx] = ResultFacet {
4463 field: field.clone(),
4464 prefix: prefix.clone(),
4465 length: *length as u32,
4466 ..Default::default()
4467 }
4468 }
4469 }
4470 QueryFacet::StringSet16 {
4471 field,
4472 prefix,
4473 length,
4474 } => {
4475 if let Some(idx) = self.facets_map.get(field)
4476 && self.facets[*idx].field_type == FieldType::StringSet16
4477 {
4478 result_query_facets[*idx] = ResultFacet {
4479 field: field.clone(),
4480 prefix: prefix.clone(),
4481 length: *length as u32,
4482 ..Default::default()
4483 }
4484 }
4485 }
4486
4487 QueryFacet::String32 {
4488 field,
4489 prefix,
4490 length,
4491 } => {
4492 if let Some(idx) = self.facets_map.get(field)
4493 && self.facets[*idx].field_type == FieldType::String32
4494 {
4495 result_query_facets[*idx] = ResultFacet {
4496 field: field.clone(),
4497 prefix: prefix.clone(),
4498 length: *length,
4499 ..Default::default()
4500 }
4501 }
4502 }
4503 QueryFacet::StringSet32 {
4504 field,
4505 prefix,
4506 length,
4507 } => {
4508 if let Some(idx) = self.facets_map.get(field)
4509 && self.facets[*idx].field_type == FieldType::StringSet32
4510 {
4511 result_query_facets[*idx] = ResultFacet {
4512 field: field.clone(),
4513 prefix: prefix.clone(),
4514 length: *length,
4515 ..Default::default()
4516 }
4517 }
4518 }
4519
4520 _ => {}
4521 };
4522 }
4523 }
4524
4525 let mut facets: AHashMap<String, Facet> = AHashMap::new();
4526 for (i, facet) in result_query_facets.iter().enumerate() {
4527 if facet.length == 0 || self.facets[i].values.is_empty() {
4528 continue;
4529 }
4530
4531 if self.facets[i].field_type == FieldType::StringSet16
4532 || self.facets[i].field_type == FieldType::StringSet32
4533 {
4534 let mut hash_map: AHashMap<String, usize> = AHashMap::new();
4535 for value in self.facets[i].values.iter() {
4536 for term in value.1.0.iter() {
4537 *hash_map.entry(term.clone()).or_insert(0) += value.1.1;
4538 }
4539 }
4540
4541 let v = hash_map
4542 .iter()
4543 .sorted_unstable_by(|a, b| b.1.cmp(a.1))
4544 .map(|(a, c)| (a.to_string(), *c))
4545 .filter(|(a, _c)| facet.prefix.is_empty() || a.starts_with(&facet.prefix))
4546 .take(facet.length as usize)
4547 .collect::<Vec<_>>();
4548
4549 if !v.is_empty() {
4550 facets.insert(facet.field.clone(), v);
4551 }
4552 } else {
4553 let v = self.facets[i]
4554 .values
4555 .iter()
4556 .sorted_unstable_by(|a, b| b.1.cmp(a.1))
4557 .map(|(a, c)| (a.to_string(), c.1))
4558 .filter(|(a, _c)| facet.prefix.is_empty() || a.starts_with(&facet.prefix))
4559 .take(facet.length as usize)
4560 .collect::<Vec<_>>();
4561
4562 if !v.is_empty() {
4563 facets.insert(facet.field.clone(), v);
4564 }
4565 }
4566 }
4567
4568 Some(facets)
4569 }
4570}
4571
4572impl Index {
4573 pub async fn current_doc_count(&self) -> usize {
4575 let mut current_doc_count = 0;
4576 for shard in self.shard_vec.iter() {
4577 current_doc_count +=
4578 shard.read().await.indexed_doc_count - shard.read().await.delete_hashset.len();
4579 }
4580 current_doc_count
4581 }
4582
4583 pub async fn uncommitted_doc_count(&self) -> usize {
4585 let mut uncommitted_doc_count = 0;
4586 for shard in self.shard_vec.iter() {
4587 uncommitted_doc_count +=
4588 shard.read().await.indexed_doc_count - shard.read().await.committed_doc_count;
4589 }
4590 uncommitted_doc_count
4591 }
4592
4593 pub async fn committed_doc_count(&self) -> usize {
4595 let mut committed_doc_count = 0;
4596 for shard in self.shard_vec.iter() {
4597 committed_doc_count += shard.read().await.committed_doc_count;
4598 }
4599 committed_doc_count
4600 }
4601
4602 pub async fn indexed_doc_count(&self) -> usize {
4604 let mut indexed_doc_count = 0;
4605 for shard in self.shard_vec.iter() {
4606 indexed_doc_count += shard.read().await.indexed_doc_count;
4607 }
4608 indexed_doc_count
4609 }
4610
4611 pub async fn indexed_vector_count(&self) -> usize {
4613 let mut indexed_vector_count = 0;
4614 for shard in self.shard_vec.iter() {
4615 indexed_vector_count += shard.read().await.indexed_vector_count;
4616 }
4617 indexed_vector_count
4618 }
4619
4620 pub async fn indexed_cluster_count(&self) -> usize {
4622 let mut indexed_cluster_count = 0;
4623 for shard in self.shard_vec.iter() {
4624 indexed_cluster_count += shard.read().await.indexed_cluster_count;
4625 }
4626 indexed_cluster_count
4627 }
4628
4629 pub async fn level_count(&self) -> usize {
4631 let mut level_count = 0;
4632 for shard in self.shard_vec.iter() {
4633 level_count += shard.read().await.level_index.len();
4634 }
4635 level_count
4636 }
4637
4638 pub async fn shard_count(&self) -> usize {
4640 self.shard_number
4641 }
4642
4643 pub fn facets_count(&self) -> usize {
4645 self.facets.len()
4646 }
4647
4648 pub async fn index_facets_minmax(&self) -> HashMap<String, MinMaxFieldJson> {
4650 let mut facets_minmax: HashMap<String, MinMaxFieldJson> = HashMap::new();
4651 for shard in self.shard_vec.iter() {
4652 for facet in shard.read().await.facets.iter() {
4653 match (&facet.min, &facet.max) {
4654 (ValueType::U8(min), ValueType::U8(max)) => {
4655 if let Some(item) = facets_minmax.get_mut(&facet.name) {
4656 *item = MinMaxFieldJson {
4657 min: (*min.min(&(item.min.as_u64().unwrap() as u8))).into(),
4658 max: (*max.min(&(item.max.as_u64().unwrap() as u8))).into(),
4659 }
4660 } else {
4661 facets_minmax.insert(
4662 facet.name.clone(),
4663 MinMaxFieldJson {
4664 min: (*min).into(),
4665 max: (*max).into(),
4666 },
4667 );
4668 }
4669 }
4670 (ValueType::U16(min), ValueType::U16(max)) => {
4671 if let Some(item) = facets_minmax.get_mut(&facet.name) {
4672 *item = MinMaxFieldJson {
4673 min: (*min.min(&(item.min.as_u64().unwrap() as u16))).into(),
4674 max: (*max.min(&(item.max.as_u64().unwrap() as u16))).into(),
4675 }
4676 } else {
4677 facets_minmax.insert(
4678 facet.name.clone(),
4679 MinMaxFieldJson {
4680 min: (*min).into(),
4681 max: (*max).into(),
4682 },
4683 );
4684 }
4685 }
4686 (ValueType::U32(min), ValueType::U32(max)) => {
4687 if let Some(item) = facets_minmax.get_mut(&facet.name) {
4688 *item = MinMaxFieldJson {
4689 min: (*min.min(&(item.min.as_u64().unwrap() as u32))).into(),
4690 max: (*max.min(&(item.max.as_u64().unwrap() as u32))).into(),
4691 }
4692 } else {
4693 facets_minmax.insert(
4694 facet.name.clone(),
4695 MinMaxFieldJson {
4696 min: (*min).into(),
4697 max: (*max).into(),
4698 },
4699 );
4700 }
4701 }
4702 (ValueType::U64(min), ValueType::U64(max)) => {
4703 if let Some(item) = facets_minmax.get_mut(&facet.name) {
4704 *item = MinMaxFieldJson {
4705 min: (*min.min(&(item.min.as_u64().unwrap()))).into(),
4706 max: (*max.min(&(item.max.as_u64().unwrap()))).into(),
4707 }
4708 } else {
4709 facets_minmax.insert(
4710 facet.name.clone(),
4711 MinMaxFieldJson {
4712 min: (*min).into(),
4713 max: (*max).into(),
4714 },
4715 );
4716 }
4717 }
4718 (ValueType::I8(min), ValueType::I8(max)) => {
4719 if let Some(item) = facets_minmax.get_mut(&facet.name) {
4720 *item = MinMaxFieldJson {
4721 min: (*min.min(&(item.min.as_i64().unwrap() as i8))).into(),
4722 max: (*max.min(&(item.max.as_i64().unwrap() as i8))).into(),
4723 }
4724 } else {
4725 facets_minmax.insert(
4726 facet.name.clone(),
4727 MinMaxFieldJson {
4728 min: (*min).into(),
4729 max: (*max).into(),
4730 },
4731 );
4732 }
4733 }
4734 (ValueType::I16(min), ValueType::I16(max)) => {
4735 if let Some(item) = facets_minmax.get_mut(&facet.name) {
4736 *item = MinMaxFieldJson {
4737 min: (*min.min(&(item.min.as_i64().unwrap() as i16))).into(),
4738 max: (*max.min(&(item.max.as_i64().unwrap() as i16))).into(),
4739 }
4740 } else {
4741 facets_minmax.insert(
4742 facet.name.clone(),
4743 MinMaxFieldJson {
4744 min: (*min).into(),
4745 max: (*max).into(),
4746 },
4747 );
4748 }
4749 }
4750 (ValueType::I32(min), ValueType::I32(max)) => {
4751 if let Some(item) = facets_minmax.get_mut(&facet.name) {
4752 *item = MinMaxFieldJson {
4753 min: (*min.min(&(item.min.as_i64().unwrap() as i32))).into(),
4754 max: (*max.min(&(item.max.as_i64().unwrap() as i32))).into(),
4755 }
4756 } else {
4757 facets_minmax.insert(
4758 facet.name.clone(),
4759 MinMaxFieldJson {
4760 min: (*min).into(),
4761 max: (*max).into(),
4762 },
4763 );
4764 }
4765 }
4766 (ValueType::I64(min), ValueType::I64(max)) => {
4767 if let Some(item) = facets_minmax.get_mut(&facet.name) {
4768 *item = MinMaxFieldJson {
4769 min: (*min.min(&(item.min.as_i64().unwrap()))).into(),
4770 max: (*max.min(&(item.max.as_i64().unwrap()))).into(),
4771 }
4772 } else {
4773 facets_minmax.insert(
4774 facet.name.clone(),
4775 MinMaxFieldJson {
4776 min: (*min).into(),
4777 max: (*max).into(),
4778 },
4779 );
4780 }
4781 }
4782 (ValueType::Timestamp(min), ValueType::Timestamp(max)) => {
4783 if let Some(item) = facets_minmax.get_mut(&facet.name) {
4784 *item = MinMaxFieldJson {
4785 min: (*min.min(&(item.min.as_i64().unwrap()))).into(),
4786 max: (*max.min(&(item.max.as_i64().unwrap()))).into(),
4787 }
4788 } else {
4789 facets_minmax.insert(
4790 facet.name.clone(),
4791 MinMaxFieldJson {
4792 min: (*min).into(),
4793 max: (*max).into(),
4794 },
4795 );
4796 }
4797 }
4798 (ValueType::F32(min), ValueType::F32(max)) => {
4799 if let Some(item) = facets_minmax.get_mut(&facet.name) {
4800 *item = MinMaxFieldJson {
4801 min: min.min(item.min.as_f64().unwrap() as f32).into(),
4802 max: max.min(item.max.as_f64().unwrap() as f32).into(),
4803 }
4804 } else {
4805 facets_minmax.insert(
4806 facet.name.clone(),
4807 MinMaxFieldJson {
4808 min: (*min).into(),
4809 max: (*max).into(),
4810 },
4811 );
4812 }
4813 }
4814 (ValueType::F64(min), ValueType::F64(max)) => {
4815 if let Some(item) = facets_minmax.get_mut(&facet.name) {
4816 *item = MinMaxFieldJson {
4817 min: min.min(item.min.as_f64().unwrap()).into(),
4818 max: max.min(item.max.as_f64().unwrap()).into(),
4819 }
4820 } else {
4821 facets_minmax.insert(
4822 facet.name.clone(),
4823 MinMaxFieldJson {
4824 min: (*min).into(),
4825 max: (*max).into(),
4826 },
4827 );
4828 }
4829 }
4830 _ => {}
4831 }
4832 }
4833 }
4834 facets_minmax
4835 }
4836
4837 pub async fn get_index_string_facets(
4846 &self,
4847 query_facets: Vec<QueryFacet>,
4848 ) -> Option<AHashMap<String, Facet>> {
4849 if self.facets.is_empty() {
4850 return None;
4851 }
4852
4853 let mut result: AHashMap<String, Facet> = AHashMap::new();
4854
4855 let mut result_facets: AHashMap<String, (AHashMap<String, usize>, u32)> = AHashMap::new();
4856 for query_facet in query_facets.iter() {
4857 match query_facet {
4858 QueryFacet::String16 {
4859 field,
4860 prefix: _,
4861 length,
4862 } => {
4863 result_facets.insert(field.into(), (AHashMap::new(), *length as u32));
4864 }
4865 QueryFacet::StringSet16 {
4866 field,
4867 prefix: _,
4868 length,
4869 } => {
4870 result_facets.insert(field.into(), (AHashMap::new(), *length as u32));
4871 }
4872
4873 QueryFacet::String32 {
4874 field,
4875 prefix: _,
4876 length,
4877 } => {
4878 result_facets.insert(field.into(), (AHashMap::new(), *length));
4879 }
4880 QueryFacet::StringSet32 {
4881 field,
4882 prefix: _,
4883 length,
4884 } => {
4885 result_facets.insert(field.into(), (AHashMap::new(), *length));
4886 }
4887
4888 _ => {}
4889 }
4890 }
4891
4892 for shard_arc in self.shard_vec.iter() {
4893 let shard = shard_arc.read().await;
4894 if !shard.facets.is_empty() {
4895 for facet in shard.facets.iter() {
4896 if let Some(existing) = result_facets.get_mut(&facet.name) {
4897 for (key, value) in facet.values.iter() {
4898 *existing.0.entry(key.clone()).or_insert(0) += value.1;
4899 }
4900 };
4901 }
4902 }
4903 }
4904
4905 for (key, value) in result_facets.iter_mut() {
4906 let sum = value
4907 .0
4908 .iter()
4909 .sorted_unstable_by(|a, b| b.1.cmp(a.1))
4910 .map(|(a, c)| (a.clone(), *c))
4911 .take(value.1 as usize)
4912 .collect::<Vec<_>>();
4913 result.insert(key.clone(), sum);
4914 }
4915
4916 Some(result)
4917 }
4918
4919 pub async fn clear_index(&mut self) {
4921 let index_path = Path::new(&self.index_path_string);
4922 let _ = fs::remove_file(index_path.join(DICTIONARY_FILENAME));
4923 if let Some(spelling_correction) = self.meta.spelling_correction.as_ref() {
4924 self.symspell_option = Some(Arc::new(RwLock::new(SymSpell::new(
4925 spelling_correction.max_dictionary_edit_distance,
4926 spelling_correction.term_length_threshold.clone(),
4927 7,
4928 spelling_correction.count_threshold,
4929 ))));
4930 }
4931
4932 let _ = fs::remove_file(index_path.join(COMPLETIONS_FILENAME));
4933 if let Some(_query_completion) = self.meta.query_completion.as_ref() {
4934 self.completion_option = Some(Arc::new(RwLock::new(PruningRadixTrie::new())));
4935 }
4936
4937 let mut result_object_list = Vec::new();
4938 for shard in self.shard_vec.iter() {
4939 let shard_clone = shard.clone();
4940 result_object_list.push(tokio::spawn(async move {
4941 shard_clone.write().await.clear_shard().await;
4942 }));
4943 }
4944 future::join_all(result_object_list).await;
4945 }
4946
4947 pub fn delete_index(&mut self) {
4949 let index_path = Path::new(&self.index_path_string);
4950
4951 let _ = fs::remove_dir_all(index_path);
4952 }
4953
4954 pub fn get_synonyms(&self) -> Result<Vec<Synonym>, String> {
4956 if let Ok(synonym_file) =
4957 File::open(Path::new(&self.index_path_string).join(SYNONYMS_FILENAME))
4958 {
4959 if let Ok(synonyms) = serde_json::from_reader(BufReader::new(synonym_file)) {
4960 Ok(synonyms)
4961 } else {
4962 Err("not found".into())
4963 }
4964 } else {
4965 Err("not found".into())
4966 }
4967 }
4968
4969 pub fn set_synonyms(&mut self, synonyms: &Vec<Synonym>) -> Result<usize, String> {
4972 serde_json::to_writer(
4973 &File::create(Path::new(&self.index_path_string).join(SYNONYMS_FILENAME)).unwrap(),
4974 &synonyms,
4975 )
4976 .unwrap();
4977
4978 self.synonyms_map = get_synonyms_map(synonyms, self.segment_number_mask1);
4979 Ok(synonyms.len())
4980 }
4981
4982 pub fn add_synonyms(&mut self, synonyms: &[Synonym]) -> Result<usize, String> {
4985 let mut merged_synonyms = if let Ok(synonym_file) =
4986 File::open(Path::new(&self.index_path_string).join(SYNONYMS_FILENAME))
4987 {
4988 serde_json::from_reader(BufReader::new(synonym_file)).unwrap_or_default()
4989 } else {
4990 Vec::new()
4991 };
4992
4993 merged_synonyms.extend(synonyms.iter().cloned());
4994
4995 serde_json::to_writer(
4996 &File::create(Path::new(&self.index_path_string).join(SYNONYMS_FILENAME)).unwrap(),
4997 &merged_synonyms,
4998 )
4999 .unwrap();
5000
5001 self.synonyms_map = get_synonyms_map(&merged_synonyms, self.segment_number_mask1);
5002 Ok(merged_synonyms.len())
5003 }
5004}
5005
5006#[allow(async_fn_in_trait)]
5008pub trait Close {
5009 async fn close(&self);
5011}
5012
5013impl Close for IndexArc {
5015 async fn close(&self) {
5017 self.commit().await;
5018
5019 let mut modified = false;
5020 for shard in self.read().await.shard_vec.iter() {
5021 if shard.read().await.modified {
5022 modified = true;
5023 break;
5024 }
5025 }
5026
5027 let mut dictionary_source = false;
5028 let mut completion_source = false;
5029 if modified {
5030 for schema_item in self.read().await.schema_map.iter() {
5031 if schema_item.1.dictionary_source {
5032 dictionary_source = true;
5033 }
5034 if schema_item.1.completion_source {
5035 completion_source = true;
5036 }
5037 }
5038 }
5039
5040 if completion_source
5041 && let Some(completion_option) = &self.read().await.completion_option.as_ref()
5042 {
5043 let trie = completion_option.read().await;
5044 let completions_path =
5045 Path::new(&self.read().await.index_path_string).join(COMPLETIONS_FILENAME);
5046
5047 _ = trie.save_completions(&completions_path, ":");
5048 }
5049
5050 if dictionary_source && let Some(symspell) = &mut self.read().await.symspell_option.as_ref()
5051 {
5052 let dictionary_path =
5053 Path::new(&self.read().await.index_path_string).join(DICTIONARY_FILENAME);
5054 let _ = symspell.read().await.save_dictionary(&dictionary_path, " ");
5055 }
5056
5057 let mut result_object_list = Vec::new();
5058 for shard in self.read().await.shard_vec.iter() {
5059 let shard_clone = shard.clone();
5060 result_object_list.push(tokio::spawn(async move {
5061 let mut mmap_options = MmapOptions::new();
5062 let mmap: MmapMut = mmap_options.len(4).map_anon().unwrap();
5063 shard_clone.write().await.index_file_mmap = mmap
5064 .make_read_only()
5065 .expect("Unable to make Mmap read-only");
5066
5067 let mut mmap_options = MmapOptions::new();
5068 let mmap: MmapMut = mmap_options.len(4).map_anon().unwrap();
5069 shard_clone.write().await.docstore_file_mmap = mmap
5070 .make_read_only()
5071 .expect("Unable to make Mmap read-only");
5072
5073 shard_clone.write().await.index_option = None;
5074 }));
5075 }
5076 future::join_all(result_object_list).await;
5077 }
5078}
5079
5080#[allow(async_fn_in_trait)]
5083pub trait DeleteDocument {
5084 async fn delete_document(&self, docid: u64);
5086}
5087
5088impl DeleteDocument for IndexArc {
5101 async fn delete_document(&self, docid: u64) {
5102 let index_ref = self.read().await;
5103 let shard_number = index_ref.shard_number as u64;
5104 let shard_id = docid % shard_number;
5105 let doc_id = docid / shard_number;
5106
5107 let mut shard_mut = index_ref.shard_vec[shard_id as usize].write().await;
5108
5109 if doc_id as usize >= shard_mut.indexed_doc_count {
5110 return;
5111 }
5112 if shard_mut.delete_hashset.insert(doc_id as usize) {
5113 let mut buffer: [u8; 8] = [0; 8];
5114 write_u64(doc_id, &mut buffer, 0);
5115 let _ = shard_mut.delete_file.write(&buffer);
5116 let _ = shard_mut.delete_file.flush();
5117 }
5118 }
5119}
5120
5121#[allow(async_fn_in_trait)]
5123pub trait DeleteDocuments {
5124 async fn delete_documents(&self, docid_vec: Vec<u64>);
5126}
5127
5128impl DeleteDocuments for IndexArc {
5137 async fn delete_documents(&self, docid_vec: Vec<u64>) {
5138 for docid in docid_vec {
5139 self.delete_document(docid).await;
5140 }
5141 }
5142}
5143
5144#[allow(clippy::too_many_arguments)]
5148#[allow(async_fn_in_trait)]
5149pub trait DeleteDocumentsByQuery {
5150 async fn delete_documents_by_query(
5154 &self,
5155 query_string: String,
5156 query_type_default: QueryType,
5157 offset: usize,
5158 length: usize,
5159 include_uncommitted: bool,
5160 field_filter: Vec<String>,
5161 facet_filter: Vec<FacetFilter>,
5162 result_sort: Vec<ResultSort>,
5163 );
5164}
5165
5166impl DeleteDocumentsByQuery for IndexArc {
5170 async fn delete_documents_by_query(
5171 &self,
5172 query_string: String,
5173 query_type_default: QueryType,
5174 offset: usize,
5175 length: usize,
5176 include_uncommitted: bool,
5177 field_filter: Vec<String>,
5178 facet_filter: Vec<FacetFilter>,
5179 result_sort: Vec<ResultSort>,
5180 ) {
5181 let rlo = self
5182 .search(
5183 query_string.to_owned(),
5184 None,
5185 query_type_default,
5186 SearchMode::Lexical,
5187 false,
5188 offset,
5189 length,
5190 ResultType::Topk,
5191 include_uncommitted,
5192 field_filter,
5193 Vec::new(),
5194 facet_filter,
5195 result_sort,
5196 QueryRewriting::SearchOnly,
5197 )
5198 .await;
5199
5200 let document_id_vec: Vec<u64> = rlo
5201 .results
5202 .iter()
5203 .map(|result| result.doc_id as u64)
5204 .collect();
5205 self.delete_documents(document_id_vec).await;
5206 }
5207}
5208
5209#[allow(async_fn_in_trait)]
5213pub trait UpdateDocument {
5214 async fn update_document(&self, id_document: (u64, Document));
5218}
5219
5220impl UpdateDocument for IndexArc {
5224 async fn update_document(&self, id_document: (u64, Document)) {
5225 self.delete_document(id_document.0).await;
5226 self.index_document(id_document.1, FileType::None).await;
5227 }
5228}
5229
5230#[allow(async_fn_in_trait)]
5234pub trait UpdateDocuments {
5235 async fn update_documents(&self, id_document_vec: Vec<(u64, Document)>);
5239}
5240
5241impl UpdateDocuments for IndexArc {
5245 async fn update_documents(&self, id_document_vec: Vec<(u64, Document)>) {
5246 let (docid_vec, document_vec): (Vec<_>, Vec<_>) = id_document_vec.into_iter().unzip();
5247 self.delete_documents(docid_vec).await;
5248 self.index_documents(document_vec).await;
5249 }
5250}
5251
5252#[allow(async_fn_in_trait)]
5254pub trait IndexDocuments {
5255 async fn index_documents(&self, document_vec: Vec<Document>);
5258}
5259
5260impl IndexDocuments for IndexArc {
5261 async fn index_documents(&self, document_vec: Vec<Document>) {
5264 for document in document_vec {
5265 self.index_document(document, FileType::None).await;
5266 }
5267 }
5268}
5269
5270#[allow(async_fn_in_trait)]
5272pub trait IndexDocument {
5273 async fn index_document(&self, document: Document, file: FileType);
5276}
5277
5278impl IndexDocument for IndexArc {
5279 async fn index_document(&self, document: Document, file: FileType) {
5282 let shard_number = self.read().await.shard_number;
5283 let docid_global_arc = self.read().await.docid_global.clone();
5284 let mut docid_global = docid_global_arc.write().await;
5285 let docid_global_clone = *docid_global;
5286 let shard_id = *docid_global % shard_number;
5287
5288 let shard_arc = self.read().await.shard_vec[shard_id].clone();
5289 let semaphore = shard_arc.read().await.semaphore.clone();
5290 let permit = semaphore.acquire_owned().await.unwrap();
5291
5292 *docid_global += 1;
5293 drop(docid_global);
5294
5295 INDEX_RUNTIME.handle().spawn(async move {
5296 shard_arc
5297 .index_document_shard(document, file, docid_global_clone)
5298 .await;
5299 drop(permit);
5300 });
5301 }
5302}
5303
5304#[allow(async_fn_in_trait)]
5306pub(crate) trait IndexDocumentShard {
5307 async fn index_document_shard(&self, document: Document, file: FileType, docid_global: usize);
5310}
5311
5312pub(crate) fn object_values_to_string_vec_recursive(value: &Value, out: &mut Vec<String>) {
5315 match value {
5316 Value::String(s) => out.push(s.clone()),
5317 Value::Array(arr) => {
5318 for v in arr {
5319 object_values_to_string_vec_recursive(v, out);
5320 }
5321 }
5322 Value::Object(map) => {
5323 for v in map.values() {
5324 object_values_to_string_vec_recursive(v, out);
5325 }
5326 }
5327 _ => {}
5328 }
5329}
5330
5331impl IndexDocumentShard for ShardArc {
5332 async fn index_document_shard(&self, document: Document, file: FileType, docid_global: usize) {
5335 let shard_arc_clone = self.clone();
5336 let shard_ref = self.read().await;
5337 let schema = shard_ref.indexed_schema_vec.clone();
5338 let ngram_indexing = shard_ref.meta.ngram_indexing;
5339 let indexed_field_vec_len = shard_ref.indexed_field_vec.len();
5340 let tokenizer_type = shard_ref.meta.tokenizer;
5341 let segment_number_mask1 = shard_ref.segment_number_mask1;
5342
5343 drop(shard_ref);
5344
5345 let token_per_field_max: u32 = u16::MAX as u32;
5346 let mut unique_terms: AHashMap<String, TermObject> = AHashMap::new();
5347 let mut field_vec: Vec<(usize, u8, u32, u32)> = Vec::new();
5348
5349 let shard_ref2 = shard_arc_clone.read().await;
5350
5351 for schema_field in schema.iter() {
5352 if !schema_field.index_lexical {
5353 continue;
5354 }
5355
5356 if let Some(field_value) = document.get(&schema_field.field) {
5357 let mut non_unique_terms: Vec<NonUniqueTermObject> = Vec::new();
5358 let mut nonunique_terms_count = 0u32;
5359
5360 let text = match schema_field.field_type {
5361 FieldType::Json => {
5362 if matches!(field_value, Value::Object { .. }) {
5363 let mut strings_vec: Vec<String> = Vec::new();
5364 object_values_to_string_vec_recursive(field_value, &mut strings_vec);
5365 strings_vec.join(" ")
5366 } else {
5367 serde_json::from_value::<String>(field_value.clone())
5368 .unwrap_or(field_value.to_string())
5369 }
5370 }
5371 FieldType::Text | FieldType::String16 | FieldType::String32 => {
5372 serde_json::from_value::<String>(field_value.clone())
5373 .unwrap_or(field_value.to_string())
5374 }
5375
5376 _ => field_value.to_string(),
5377 };
5378
5379 let mut query_type_mut = QueryType::Union;
5380
5381 tokenizer(
5382 &shard_ref2,
5383 &text,
5384 &mut unique_terms,
5385 &mut non_unique_terms,
5386 tokenizer_type,
5387 segment_number_mask1,
5388 &mut nonunique_terms_count,
5389 token_per_field_max,
5390 MAX_POSITIONS_PER_TERM,
5391 false,
5392 &mut query_type_mut,
5393 ngram_indexing,
5394 schema_field.indexed_field_id,
5395 indexed_field_vec_len,
5396 )
5397 .await;
5398
5399 let document_length_compressed: u8 = int_to_byte4(nonunique_terms_count);
5400 let document_length_normalized: u32 =
5401 DOCUMENT_LENGTH_COMPRESSION[document_length_compressed as usize];
5402 field_vec.push((
5403 schema_field.indexed_field_id,
5404 document_length_compressed,
5405 document_length_normalized,
5406 nonunique_terms_count,
5407 ));
5408 }
5409 }
5410 drop(shard_ref2);
5411
5412 let ngrams: Vec<String> = unique_terms
5413 .iter()
5414 .filter(|term| term.1.ngram_type != NgramType::SingleTerm)
5415 .map(|term| term.1.term.clone())
5416 .collect();
5417
5418 for term in ngrams.iter() {
5419 let ngram = unique_terms.get(term).unwrap();
5420
5421 match ngram.ngram_type {
5422 NgramType::SingleTerm => {}
5423 NgramType::NgramFF | NgramType::NgramFR | NgramType::NgramRF => {
5424 let term_ngram1 = ngram.term_ngram_1.clone();
5425 let term_ngram2 = ngram.term_ngram_0.clone();
5426
5427 for indexed_field_id in 0..indexed_field_vec_len {
5428 let positions_count_ngram1 =
5429 unique_terms[&term_ngram1].field_positions_vec[indexed_field_id].len();
5430 let positions_count_ngram2 =
5431 unique_terms[&term_ngram2].field_positions_vec[indexed_field_id].len();
5432 let ngram = unique_terms.get_mut(term).unwrap();
5433
5434 if positions_count_ngram1 > 0 {
5435 ngram
5436 .field_vec_ngram1
5437 .push((indexed_field_id, positions_count_ngram1 as u32));
5438 }
5439 if positions_count_ngram2 > 0 {
5440 ngram
5441 .field_vec_ngram2
5442 .push((indexed_field_id, positions_count_ngram2 as u32));
5443 }
5444 }
5445 }
5446 _ => {
5447 let term_ngram1 = ngram.term_ngram_2.clone();
5448 let term_ngram2 = ngram.term_ngram_1.clone();
5449 let term_ngram3 = ngram.term_ngram_0.clone();
5450
5451 for indexed_field_id in 0..indexed_field_vec_len {
5452 let positions_count_ngram1 =
5453 unique_terms[&term_ngram1].field_positions_vec[indexed_field_id].len();
5454 let positions_count_ngram2 =
5455 unique_terms[&term_ngram2].field_positions_vec[indexed_field_id].len();
5456 let positions_count_ngram3 =
5457 unique_terms[&term_ngram3].field_positions_vec[indexed_field_id].len();
5458 let ngram = unique_terms.get_mut(term).unwrap();
5459
5460 if positions_count_ngram1 > 0 {
5461 ngram
5462 .field_vec_ngram1
5463 .push((indexed_field_id, positions_count_ngram1 as u32));
5464 }
5465 if positions_count_ngram2 > 0 {
5466 ngram
5467 .field_vec_ngram2
5468 .push((indexed_field_id, positions_count_ngram2 as u32));
5469 }
5470 if positions_count_ngram3 > 0 {
5471 ngram
5472 .field_vec_ngram3
5473 .push((indexed_field_id, positions_count_ngram3 as u32));
5474 }
5475 }
5476 }
5477 }
5478 }
5479
5480 let document_item = DocumentItem {
5481 document,
5482 unique_terms,
5483 field_vec,
5484 };
5485
5486 shard_arc_clone
5487 .index_document_shard_2(document_item, file, docid_global)
5488 .await;
5489 }
5490}
5491
5492#[allow(async_fn_in_trait)]
5493pub(crate) trait IndexDocumentShard2 {
5494 async fn index_document_shard_2(
5495 &self,
5496 document_item: DocumentItem,
5497 file: FileType,
5498 docid_global: usize,
5499 );
5500}
5501
5502impl IndexDocumentShard2 for ShardArc {
5503 async fn index_document_shard_2(
5504 &self,
5505 document_item: DocumentItem,
5506 file: FileType,
5507 docid_global: usize,
5508 ) {
5509 let mut shard_mut = self.write().await;
5510
5511 let docid_local = docid_global / shard_mut.shard_number;
5512
5513 shard_mut.indexed_doc_count = docid_local + 1;
5514
5515 let do_commit = shard_mut.block_id != docid_local >> 16;
5516 if do_commit {
5517 if shard_mut.is_vector_indexing {
5518 shard_mut.commit_vector_shard().await;
5519 }
5520 shard_mut.commit_lexical_shard(docid_local).await;
5521
5522 shard_mut.block_id = docid_local >> 16;
5523 }
5524
5525 if shard_mut.is_vector_indexing {
5526 shard_mut
5527 .index_vector_shard(docid_local, &document_item.document)
5528 .await;
5529 }
5530
5531 if !shard_mut.facets.is_empty() {
5532 let facets_size_sum = shard_mut.facets_size_sum;
5533 for i in 0..shard_mut.facets.len() {
5534 let facet = &mut shard_mut.facets[i];
5535 if let Some(field_value) = document_item.document.get(&facet.name) {
5536 let address = (facets_size_sum * docid_local) + facet.offset;
5537
5538 match facet.field_type {
5539 FieldType::U8 => {
5540 let value = field_value.as_u64().unwrap_or_default() as u8;
5541 match (&facet.min, &facet.max) {
5542 (ValueType::U8(min), ValueType::U8(max)) => {
5543 if value < *min {
5544 facet.min = ValueType::U8(value);
5545 }
5546 if value > *max {
5547 facet.max = ValueType::U8(value);
5548 }
5549 }
5550 (ValueType::None, ValueType::None) => {
5551 facet.min = ValueType::U8(value);
5552 facet.max = ValueType::U8(value);
5553 }
5554 _ => {}
5555 }
5556 shard_mut.facets_file_mmap[address] = value
5557 }
5558 FieldType::U16 => {
5559 let value = field_value.as_u64().unwrap_or_default() as u16;
5560 match (&facet.min, &facet.max) {
5561 (ValueType::U16(min), ValueType::U16(max)) => {
5562 if value < *min {
5563 facet.min = ValueType::U16(value);
5564 }
5565 if value > *max {
5566 facet.max = ValueType::U16(value);
5567 }
5568 }
5569 (ValueType::None, ValueType::None) => {
5570 facet.min = ValueType::U16(value);
5571 facet.max = ValueType::U16(value);
5572 }
5573 _ => {}
5574 }
5575 write_u16(value, &mut shard_mut.facets_file_mmap, address)
5576 }
5577 FieldType::U32 => {
5578 let value = field_value.as_u64().unwrap_or_default() as u32;
5579 match (&facet.min, &facet.max) {
5580 (ValueType::U32(min), ValueType::U32(max)) => {
5581 if value < *min {
5582 facet.min = ValueType::U32(value);
5583 }
5584 if value > *max {
5585 facet.max = ValueType::U32(value);
5586 }
5587 }
5588 (ValueType::None, ValueType::None) => {
5589 facet.min = ValueType::U32(value);
5590 facet.max = ValueType::U32(value);
5591 }
5592 _ => {}
5593 }
5594 write_u32(value, &mut shard_mut.facets_file_mmap, address)
5595 }
5596 FieldType::U64 => {
5597 let value = field_value.as_u64().unwrap_or_default();
5598 match (&facet.min, &facet.max) {
5599 (ValueType::U64(min), ValueType::U64(max)) => {
5600 if value < *min {
5601 facet.min = ValueType::U64(value);
5602 }
5603 if value > *max {
5604 facet.max = ValueType::U64(value);
5605 }
5606 }
5607 (ValueType::None, ValueType::None) => {
5608 facet.min = ValueType::U64(value);
5609 facet.max = ValueType::U64(value);
5610 }
5611 _ => {}
5612 }
5613 write_u64(value, &mut shard_mut.facets_file_mmap, address)
5614 }
5615 FieldType::I8 => {
5616 let value = field_value.as_i64().unwrap_or_default() as i8;
5617 match (&facet.min, &facet.max) {
5618 (ValueType::I8(min), ValueType::I8(max)) => {
5619 if value < *min {
5620 facet.min = ValueType::I8(value);
5621 }
5622 if value > *max {
5623 facet.max = ValueType::I8(value);
5624 }
5625 }
5626 (ValueType::None, ValueType::None) => {
5627 facet.min = ValueType::I8(value);
5628 facet.max = ValueType::I8(value);
5629 }
5630 _ => {}
5631 }
5632 write_i8(value, &mut shard_mut.facets_file_mmap, address)
5633 }
5634 FieldType::I16 => {
5635 let value = field_value.as_i64().unwrap_or_default() as i16;
5636 match (&facet.min, &facet.max) {
5637 (ValueType::I16(min), ValueType::I16(max)) => {
5638 if value < *min {
5639 facet.min = ValueType::I16(value);
5640 }
5641 if value > *max {
5642 facet.max = ValueType::I16(value);
5643 }
5644 }
5645 (ValueType::None, ValueType::None) => {
5646 facet.min = ValueType::I16(value);
5647 facet.max = ValueType::I16(value);
5648 }
5649 _ => {}
5650 }
5651 write_i16(value, &mut shard_mut.facets_file_mmap, address)
5652 }
5653 FieldType::I32 => {
5654 let value = field_value.as_i64().unwrap_or_default() as i32;
5655 match (&facet.min, &facet.max) {
5656 (ValueType::I32(min), ValueType::I32(max)) => {
5657 if value < *min {
5658 facet.min = ValueType::I32(value);
5659 }
5660 if value > *max {
5661 facet.max = ValueType::I32(value);
5662 }
5663 }
5664 (ValueType::None, ValueType::None) => {
5665 facet.min = ValueType::I32(value);
5666 facet.max = ValueType::I32(value);
5667 }
5668 _ => {}
5669 }
5670 write_i32(value, &mut shard_mut.facets_file_mmap, address)
5671 }
5672 FieldType::I64 => {
5673 let value = field_value.as_i64().unwrap_or_default();
5674 match (&facet.min, &facet.max) {
5675 (ValueType::I64(min), ValueType::I64(max)) => {
5676 if value < *min {
5677 facet.min = ValueType::I64(value);
5678 }
5679 if value > *max {
5680 facet.max = ValueType::I64(value);
5681 }
5682 }
5683 (ValueType::None, ValueType::None) => {
5684 facet.min = ValueType::I64(value);
5685 facet.max = ValueType::I64(value);
5686 }
5687 _ => {}
5688 }
5689 write_i64(value, &mut shard_mut.facets_file_mmap, address)
5690 }
5691 FieldType::Timestamp => {
5692 let value = field_value.as_i64().unwrap_or_default();
5693 match (&facet.min, &facet.max) {
5694 (ValueType::Timestamp(min), ValueType::Timestamp(max)) => {
5695 if value < *min {
5696 facet.min = ValueType::Timestamp(value);
5697 }
5698 if value > *max {
5699 facet.max = ValueType::Timestamp(value);
5700 }
5701 }
5702 (ValueType::None, ValueType::None) => {
5703 facet.min = ValueType::Timestamp(value);
5704 facet.max = ValueType::Timestamp(value);
5705 }
5706 _ => {}
5707 }
5708
5709 write_i64(value, &mut shard_mut.facets_file_mmap, address);
5710 }
5711 FieldType::F32 => {
5712 let value = field_value.as_f64().unwrap_or_default() as f32;
5713 match (&facet.min, &facet.max) {
5714 (ValueType::F32(min), ValueType::F32(max)) => {
5715 if value < *min {
5716 facet.min = ValueType::F32(value);
5717 }
5718 if value > *max {
5719 facet.max = ValueType::F32(value);
5720 }
5721 }
5722 (ValueType::None, ValueType::None) => {
5723 facet.min = ValueType::F32(value);
5724 facet.max = ValueType::F32(value);
5725 }
5726 _ => {}
5727 }
5728
5729 write_f32(value, &mut shard_mut.facets_file_mmap, address)
5730 }
5731 FieldType::F64 => {
5732 let value = field_value.as_f64().unwrap_or_default();
5733 match (&facet.min, &facet.max) {
5734 (ValueType::F64(min), ValueType::F64(max)) => {
5735 if value < *min {
5736 facet.min = ValueType::F64(value);
5737 }
5738 if value > *max {
5739 facet.max = ValueType::F64(value);
5740 }
5741 }
5742 (ValueType::None, ValueType::None) => {
5743 facet.min = ValueType::F64(value);
5744 facet.max = ValueType::F64(value);
5745 }
5746 _ => {}
5747 }
5748
5749 write_f64(value, &mut shard_mut.facets_file_mmap, address)
5750 }
5751 FieldType::String16 if facet.values.len() < u16::MAX as usize => {
5752 let key = serde_json::from_value::<String>(field_value.clone())
5753 .unwrap_or(field_value.to_string());
5754
5755 let key_string = key.clone();
5756 let key = vec![key];
5757
5758 facet.values.entry(key_string.clone()).or_insert((key, 0)).1 += 1;
5759
5760 let facet_value_id =
5761 facet.values.get_index_of(&key_string).unwrap() as u16;
5762 write_u16(facet_value_id, &mut shard_mut.facets_file_mmap, address)
5763 }
5764
5765 FieldType::StringSet16 if facet.values.len() < u16::MAX as usize => {
5766 let mut key: Vec<String> =
5767 serde_json::from_value(field_value.clone()).unwrap();
5768 key.sort();
5769
5770 let key_string = key.join("_");
5771 facet.values.entry(key_string.clone()).or_insert((key, 0)).1 += 1;
5772
5773 let facet_value_id =
5774 facet.values.get_index_of(&key_string).unwrap() as u16;
5775 write_u16(facet_value_id, &mut shard_mut.facets_file_mmap, address)
5776 }
5777
5778 FieldType::String32 if facet.values.len() < u32::MAX as usize => {
5779 let key = serde_json::from_value::<String>(field_value.clone())
5780 .unwrap_or(field_value.to_string());
5781
5782 let key_string = key.clone();
5783 let key = vec![key];
5784
5785 facet.values.entry(key_string.clone()).or_insert((key, 0)).1 += 1;
5786
5787 let facet_value_id =
5788 facet.values.get_index_of(&key_string).unwrap() as u32;
5789 write_u32(facet_value_id, &mut shard_mut.facets_file_mmap, address)
5790 }
5791
5792 FieldType::StringSet32 if facet.values.len() < u32::MAX as usize => {
5793 let mut key: Vec<String> =
5794 serde_json::from_value(field_value.clone()).unwrap();
5795 key.sort();
5796
5797 let key_string = key.join("_");
5798 facet.values.entry(key_string.clone()).or_insert((key, 0)).1 += 1;
5799
5800 let facet_value_id =
5801 facet.values.get_index_of(&key_string).unwrap() as u32;
5802 write_u32(facet_value_id, &mut shard_mut.facets_file_mmap, address)
5803 }
5804
5805 FieldType::Point => {
5806 if let Ok(point) = serde_json::from_value::<Point>(field_value.clone())
5807 && point.len() == 2
5808 {
5809 if point[0] >= -90.0
5810 && point[0] <= 90.0
5811 && point[1] >= -180.0
5812 && point[1] <= 180.0
5813 {
5814 let morton_code = encode_morton_2_d(&point);
5815 write_u64(morton_code, &mut shard_mut.facets_file_mmap, address)
5816 } else {
5817 println!(
5818 "outside valid coordinate range: {} {}",
5819 point[0], point[1]
5820 );
5821 }
5822 }
5823 }
5824
5825 _ => {}
5826 };
5827 }
5828 }
5829 }
5830
5831 if !shard_mut.uncommitted {
5832 if shard_mut.segments_level0[0].positions_compressed.is_empty() {
5833 for strip0 in shard_mut.segments_level0.iter_mut() {
5834 strip0.positions_compressed = vec![0; MAX_POSITIONS_PER_TERM * 2];
5835 }
5836 }
5837 shard_mut.uncommitted = true;
5838 }
5839
5840 let mut longest_field_id: usize = 0;
5841 let mut longest_field_length: u32 = 0;
5842 for value in document_item.field_vec {
5843 if docid_local == 0 && value.3 > longest_field_length {
5844 longest_field_id = value.0;
5845 longest_field_length = value.3;
5846 }
5847
5848 shard_mut.document_length_compressed_array[value.0]
5849 [docid_local & 0b11111111_11111111] = value.1;
5850 shard_mut.positions_sum_normalized += value.2 as u64;
5851 shard_mut.indexed_field_vec[value.0].field_length_sum += value.2 as usize;
5852 }
5853
5854 if docid_local == 0 && shard_mut.is_lexical_indexing {
5855 if !shard_mut.longest_field_auto {
5856 longest_field_id = shard_mut.longest_field_id;
5857 }
5858 shard_mut.longest_field_id = longest_field_id;
5859 shard_mut.indexed_field_vec[longest_field_id].is_longest_field = true;
5860 if shard_mut.longest_field_auto && shard_mut.indexed_field_vec.len() > 1 {
5861 println!(
5862 "detect longest field id {} name {} length {}",
5863 longest_field_id,
5864 shard_mut.indexed_field_vec[longest_field_id].schema_field_name,
5865 longest_field_length
5866 );
5867 }
5868 }
5869
5870 let mut unique_terms = document_item.unique_terms;
5871 if !shard_mut.synonyms_map.is_empty() {
5872 let unique_terms_clone = unique_terms.clone();
5873 for term in unique_terms_clone.iter() {
5874 if term.1.ngram_type == NgramType::SingleTerm {
5875 let synonym = shard_mut.synonyms_map.get(&term.1.key_hash).cloned();
5876 if let Some(synonym) = synonym {
5877 for synonym_term in synonym {
5878 let mut term_clone = term.1.clone();
5879 term_clone.key_hash = synonym_term.1.0;
5880 term_clone.key0 = synonym_term.1.1;
5881 term_clone.term = synonym_term.0.clone();
5882
5883 if let Some(existing) = unique_terms.get_mut(&synonym_term.0) {
5884 existing
5885 .field_positions_vec
5886 .iter_mut()
5887 .zip(term_clone.field_positions_vec.iter())
5888 .for_each(|(x1, x2)| {
5889 x1.extend_from_slice(x2);
5890 x1.sort_unstable();
5891 });
5892 } else {
5893 unique_terms.insert(synonym_term.0.clone(), term_clone);
5894 };
5895 }
5896 }
5897 }
5898 }
5899 }
5900
5901 for term in unique_terms {
5902 shard_mut.index_posting(term.1, docid_local, false, 0, 0, 0);
5903 }
5904
5905 match file {
5906 FileType::Path(file_path) => {
5907 if let Err(e) = shard_mut.copy_file(&file_path, docid_local) {
5908 println!("can't copy PDF {} {}", file_path.display(), e);
5909 }
5910 }
5911
5912 FileType::Bytes(file_path, file_bytes) => {
5913 if let Err(e) = shard_mut.write_file(&file_bytes, docid_local) {
5914 println!("can't copy PDF {} {}", file_path.display(), e);
5915 }
5916 }
5917
5918 _ => {}
5919 }
5920
5921 if !shard_mut.stored_field_names.is_empty() {
5922 shard_mut.store_document(docid_local, document_item.document);
5923 }
5924
5925 if do_commit {
5926 drop(shard_mut);
5927 warmup(self).await;
5928 }
5929 }
5930}
5931
5932pub(crate) struct DocumentItem {
5933 pub document: Document,
5934 pub unique_terms: AHashMap<String, TermObject>,
5935 pub field_vec: Vec<(usize, u8, u32, u32)>,
5936}