mirror of
https://github.com/quickwit-oss/tantivy.git
synced 2025-12-23 02:29:57 +00:00
Complete Spatial/Geometry type integration.
Addressed all `todo!()` markers created when adding `Spatial` field type and `Geometry` value type to existing code paths: - Dynamic field handling: `Geometry` not supported in dynamic JSON fields, return `unimplemented!()` consistently with other complex types. - Fast field writer: Panic if geometry routed incorrectly (internal error.) - `OwnedValue` serialization: Implement `Geometry` to GeoJSON serialization and reference-to-owned conversion. - Field type: Return `None` for `get_index_record_option()` since spatial fields use BKD trees, not inverted index. - Space usage tracking: Add spatial field to `SegmentSpaceUsage` with proper integration through `SegmentReader`. - Spatial query explain: Implement `explain()` method following pattern of other binary/constant-score queries. Fixed `MultiPolygon` deserialization bug: count total points across all rings, not number of rings. Added clippy expects for legitimate too_many_arguments cases in geometric predicates.
This commit is contained in:
committed by
Paul Masurel
parent
68009bb25b
commit
9f10279681
@@ -227,7 +227,9 @@ pub(crate) fn index_json_value<'a, V: Value<'a>>(
|
||||
ReferenceValueLeaf::IpAddr(_) => {
|
||||
unimplemented!("IP address support in dynamic fields is not yet implemented")
|
||||
}
|
||||
ReferenceValueLeaf::Geometry(_) => todo!(),
|
||||
ReferenceValueLeaf::Geometry(_) => {
|
||||
unimplemented!("Geometry support in dynamic fields is not implemented")
|
||||
}
|
||||
},
|
||||
ReferenceValue::Array(elements) => {
|
||||
for val in elements {
|
||||
|
||||
@@ -189,7 +189,9 @@ impl FastFieldsWriter {
|
||||
.record_str(doc_id, field_name, &token.text);
|
||||
}
|
||||
}
|
||||
ReferenceValueLeaf::Geometry(_) => todo!(),
|
||||
ReferenceValueLeaf::Geometry(_) => {
|
||||
panic!("Geometry fields should not be routed to fast field writer")
|
||||
}
|
||||
},
|
||||
ReferenceValue::Array(val) => {
|
||||
// TODO: Check this is the correct behaviour we want.
|
||||
@@ -321,7 +323,9 @@ fn record_json_value_to_columnar_writer<'a, V: Value<'a>>(
|
||||
"Pre-tokenized string support in dynamic fields is not yet implemented"
|
||||
)
|
||||
}
|
||||
ReferenceValueLeaf::Geometry(_) => todo!(),
|
||||
ReferenceValueLeaf::Geometry(_) => {
|
||||
unimplemented!("Geometry support in dynamic fields is not yet implemented")
|
||||
}
|
||||
},
|
||||
ReferenceValue::Array(elements) => {
|
||||
for el in elements {
|
||||
|
||||
@@ -470,6 +470,7 @@ impl SegmentReader {
|
||||
self.positions_composite.space_usage(),
|
||||
self.fast_fields_readers.space_usage(self.schema())?,
|
||||
self.fieldnorm_readers.space_usage(),
|
||||
self.spatial_readers.space_usage(),
|
||||
self.get_store_reader(0)?.space_usage(),
|
||||
self.alive_bitset_opt
|
||||
.as_ref()
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
use common::BitSet;
|
||||
|
||||
use crate::query::{BitSetDocSet, Query, Scorer, Weight};
|
||||
use crate::query::explanation::does_not_match;
|
||||
use crate::query::{BitSetDocSet, Explanation, Query, Scorer, Weight};
|
||||
use crate::schema::Field;
|
||||
use crate::spatial::bkd::{search_intersects, Segment};
|
||||
use crate::spatial::writer::as_point_i32;
|
||||
@@ -96,10 +97,24 @@ impl Weight for SpatialWeight {
|
||||
}
|
||||
fn explain(
|
||||
&self,
|
||||
_reader: &crate::SegmentReader,
|
||||
_doc: DocId,
|
||||
reader: &crate::SegmentReader,
|
||||
doc: DocId,
|
||||
) -> crate::Result<super::Explanation> {
|
||||
todo!();
|
||||
let mut scorer = self.scorer(reader, 1.0)?;
|
||||
if scorer.seek(doc) != doc {
|
||||
return Err(does_not_match(doc));
|
||||
}
|
||||
let query_type_desc = match self.query_type {
|
||||
SpatialQueryType::Intersects => "SpatialQuery::Intersects",
|
||||
};
|
||||
let score = scorer.score();
|
||||
let mut explanation = Explanation::new(query_type_desc, score);
|
||||
explanation.add_context(format!(
|
||||
"bounds: [({}, {}), ({}, {})]",
|
||||
self.bounds[0].0, self.bounds[0].1, self.bounds[1].0, self.bounds[1].1,
|
||||
));
|
||||
explanation.add_context(format!("field: {:?}", self.field));
|
||||
Ok(explanation)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -466,7 +466,6 @@ impl<'a> CompactDocValue<'a> {
|
||||
.map(Into::into)
|
||||
.map(ReferenceValueLeaf::PreTokStr)
|
||||
.map(Into::into),
|
||||
// ValueType::Geometry => todo!(),
|
||||
ValueType::Geometry => self
|
||||
.container
|
||||
.read_from::<Geometry>(addr)
|
||||
|
||||
@@ -208,7 +208,7 @@ impl serde::Serialize for OwnedValue {
|
||||
}
|
||||
}
|
||||
OwnedValue::Array(ref array) => array.serialize(serializer),
|
||||
OwnedValue::Geometry(_) => todo!(),
|
||||
OwnedValue::Geometry(ref geometry) => geometry.to_geojson().serialize(serializer),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -296,7 +296,7 @@ impl<'a, V: Value<'a>> From<ReferenceValue<'a, V>> for OwnedValue {
|
||||
ReferenceValueLeaf::IpAddr(val) => OwnedValue::IpAddr(val),
|
||||
ReferenceValueLeaf::Bool(val) => OwnedValue::Bool(val),
|
||||
ReferenceValueLeaf::PreTokStr(val) => OwnedValue::PreTokStr(*val.clone()),
|
||||
ReferenceValueLeaf::Geometry(_) => todo!(),
|
||||
ReferenceValueLeaf::Geometry(val) => OwnedValue::Geometry(*val.clone()),
|
||||
},
|
||||
ReferenceValue::Array(val) => {
|
||||
OwnedValue::Array(val.map(|v| v.as_value().into()).collect())
|
||||
|
||||
@@ -359,7 +359,8 @@ impl FieldType {
|
||||
None
|
||||
}
|
||||
}
|
||||
FieldType::Spatial(_) => todo!(),
|
||||
FieldType::Spatial(_) => None, /* Geometry types cannot be indexed in the inverted
|
||||
* index. */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,7 @@ pub struct SegmentSpaceUsage {
|
||||
positions: PerFieldSpaceUsage,
|
||||
fast_fields: PerFieldSpaceUsage,
|
||||
fieldnorms: PerFieldSpaceUsage,
|
||||
spatial: PerFieldSpaceUsage,
|
||||
|
||||
store: StoreSpaceUsage,
|
||||
|
||||
@@ -86,6 +87,7 @@ impl SegmentSpaceUsage {
|
||||
positions: PerFieldSpaceUsage,
|
||||
fast_fields: PerFieldSpaceUsage,
|
||||
fieldnorms: PerFieldSpaceUsage,
|
||||
spatial: PerFieldSpaceUsage,
|
||||
store: StoreSpaceUsage,
|
||||
deletes: ByteCount,
|
||||
) -> SegmentSpaceUsage {
|
||||
@@ -94,6 +96,7 @@ impl SegmentSpaceUsage {
|
||||
+ positions.total()
|
||||
+ fast_fields.total()
|
||||
+ fieldnorms.total()
|
||||
+ spatial.total()
|
||||
+ store.total()
|
||||
+ deletes;
|
||||
SegmentSpaceUsage {
|
||||
@@ -103,6 +106,7 @@ impl SegmentSpaceUsage {
|
||||
positions,
|
||||
fast_fields,
|
||||
fieldnorms,
|
||||
spatial,
|
||||
store,
|
||||
deletes,
|
||||
total,
|
||||
@@ -121,11 +125,11 @@ impl SegmentSpaceUsage {
|
||||
Positions => PerField(self.positions().clone()),
|
||||
FastFields => PerField(self.fast_fields().clone()),
|
||||
FieldNorms => PerField(self.fieldnorms().clone()),
|
||||
Spatial => PerField(self.spatial().clone()),
|
||||
Terms => PerField(self.termdict().clone()),
|
||||
SegmentComponent::Store => ComponentSpaceUsage::Store(self.store().clone()),
|
||||
SegmentComponent::TempStore => ComponentSpaceUsage::Store(self.store().clone()),
|
||||
Delete => Basic(self.deletes()),
|
||||
Spatial => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,6 +163,11 @@ impl SegmentSpaceUsage {
|
||||
&self.fieldnorms
|
||||
}
|
||||
|
||||
/// Space usage for field norms
|
||||
pub fn spatial(&self) -> &PerFieldSpaceUsage {
|
||||
&self.spatial
|
||||
}
|
||||
|
||||
/// Space usage for stored documents
|
||||
pub fn store(&self) -> &StoreSpaceUsage {
|
||||
&self.store
|
||||
|
||||
@@ -481,6 +481,7 @@ pub fn search_intersects(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
fn line_intersects_line(
|
||||
x1: i32,
|
||||
y1: i32,
|
||||
@@ -572,6 +573,7 @@ fn triangle_within(triangle: &Triangle, query: &[i32; 4]) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
fn point_in_triangle(
|
||||
px: i32,
|
||||
py: i32,
|
||||
|
||||
@@ -353,8 +353,9 @@ impl BinarySerializable for Geometry {
|
||||
let ring_count = VInt::deserialize(reader)?.0 as usize;
|
||||
let mut rings = Vec::new();
|
||||
for _ in 0..ring_count {
|
||||
rings.push(VInt::deserialize(reader)?.0 as usize);
|
||||
count += 1;
|
||||
let point_count = VInt::deserialize(reader)?.0 as usize;
|
||||
rings.push(point_count);
|
||||
count += point_count;
|
||||
}
|
||||
polygons.push(rings);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user