diff --git a/src/aggregation/agg_tests.rs b/src/aggregation/agg_tests.rs index df3c85b50..1fea7fe6f 100644 --- a/src/aggregation/agg_tests.rs +++ b/src/aggregation/agg_tests.rs @@ -624,6 +624,65 @@ fn test_aggregation_on_json_object() { ); } +#[test] +fn test_aggregation_on_nested_json_object() { + let mut schema_builder = Schema::builder(); + let json = schema_builder.add_json_field("json.blub", FAST); + let schema = schema_builder.build(); + let index = Index::create_in_ram(schema); + let mut index_writer: IndexWriter = index.writer_for_tests().unwrap(); + index_writer + .add_document(doc!(json => json!({"color.dot": "red", "color": {"nested":"red"} }))) + .unwrap(); + index_writer + .add_document(doc!(json => json!({"color.dot": "blue", "color": {"nested":"blue"} }))) + .unwrap(); + index_writer.commit().unwrap(); + let reader = index.reader().unwrap(); + let searcher = reader.searcher(); + + let agg: Aggregations = serde_json::from_value(json!({ + "jsonagg1": { + "terms": { + "field": "json\\.blub.color\\.dot", + } + }, + "jsonagg2": { + "terms": { + "field": "json\\.blub.color.nested", + } + } + + })) + .unwrap(); + + let aggregation_collector = get_collector(agg); + let aggregation_results = searcher.search(&AllQuery, &aggregation_collector).unwrap(); + let aggregation_res_json = serde_json::to_value(aggregation_results).unwrap(); + assert_eq!( + &aggregation_res_json, + &serde_json::json!({ + "jsonagg1": { + "buckets": [ + {"doc_count": 1, "key": "blue"}, + {"doc_count": 1, "key": "red"} + ], + "doc_count_error_upper_bound": 0, + "sum_other_doc_count": 0 + }, + "jsonagg2": { + "buckets": [ + {"doc_count": 1, "key": "blue"}, + {"doc_count": 1, "key": "red"} + ], + "doc_count_error_upper_bound": 0, + "sum_other_doc_count": 0 + } + + }) + ); +} + #[test] fn test_aggregation_on_json_object_empty_columns() { let mut schema_builder = Schema::builder(); diff --git a/src/core/json_utils.rs b/src/core/json_utils.rs index 6a5387cf0..a9060bc6a 100644 --- a/src/core/json_utils.rs +++ b/src/core/json_utils.rs @@ -320,7 +320,7 @@ pub struct JsonTermWriter<'a> { /// In other words, /// - `k8s.node` ends up as `["k8s", "node"]`. /// - `k8s\.node` ends up as `["k8s.node"]`. -fn split_json_path(json_path: &str) -> Vec { +pub fn split_json_path(json_path: &str) -> Vec { let mut escaped_state: bool = false; let mut json_path_segments = Vec::new(); let mut buffer = String::new(); diff --git a/src/fastfield/mod.rs b/src/fastfield/mod.rs index 1c9b3d5af..65e4c03bf 100644 --- a/src/fastfield/mod.rs +++ b/src/fastfield/mod.rs @@ -1288,11 +1288,18 @@ mod tests { index_writer.commit().unwrap(); let searcher = index.reader().unwrap().searcher(); let fast_field_reader = searcher.segment_reader(0u32).fast_fields(); + // Supported for now, maybe dropped in the future. let column = fast_field_reader .column_opt::("jsonfield.attr.age") .unwrap() .unwrap(); let vals: Vec = column.values_for_doc(0u32).collect(); assert_eq!(&vals, &[33]); + let column = fast_field_reader + .column_opt::("jsonfield\\.attr.age") + .unwrap() + .unwrap(); + let vals: Vec = column.values_for_doc(0u32).collect(); + assert_eq!(&vals, &[33]); } } diff --git a/src/schema/schema.rs b/src/schema/schema.rs index c6bf7b932..e19c942ef 100644 --- a/src/schema/schema.rs +++ b/src/schema/schema.rs @@ -8,6 +8,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; use super::ip_options::IpAddrOptions; use super::*; +use crate::json_utils::split_json_path; use crate::schema::bytes_options::BytesOptions; use crate::TantivyError; @@ -328,12 +329,19 @@ impl Schema { if let Some(field) = self.0.fields_map.get(full_path) { return Some((*field, "")); } + let mut splitting_period_pos: Vec = locate_splitting_dots(full_path); while let Some(pos) = splitting_period_pos.pop() { let (prefix, suffix) = full_path.split_at(pos); + if let Some(field) = self.0.fields_map.get(prefix) { return Some((*field, &suffix[1..])); } + // JSON path may contain a dot, for now we try both variants to find the field. + let prefix = split_json_path(prefix).join("."); + if let Some(field) = self.0.fields_map.get(&prefix) { + return Some((*field, &suffix[1..])); + } } None }