mirror of
https://github.com/meilisearch/meilisearch.git
synced 2024-11-27 04:25:06 +08:00
fix the filterable fields
This commit is contained in:
parent
e5af3ac65c
commit
7483c7513a
@ -26,6 +26,7 @@ enum FilterError<'a> {
|
|||||||
BadGeoLat(f64),
|
BadGeoLat(f64),
|
||||||
BadGeoLng(f64),
|
BadGeoLng(f64),
|
||||||
Reserved(&'a str),
|
Reserved(&'a str),
|
||||||
|
InternalError,
|
||||||
}
|
}
|
||||||
impl<'a> std::error::Error for FilterError<'a> {}
|
impl<'a> std::error::Error for FilterError<'a> {}
|
||||||
|
|
||||||
@ -46,6 +47,7 @@ impl<'a> Display for FilterError<'a> {
|
|||||||
Self::BadGeo(keyword) => write!(f, "`{}` is a reserved keyword and thus can't be used as a filter expression. Use the _geoRadius(latitude, longitude, distance) built-in rule to filter on _geo field coordinates.", keyword),
|
Self::BadGeo(keyword) => write!(f, "`{}` is a reserved keyword and thus can't be used as a filter expression. Use the _geoRadius(latitude, longitude, distance) built-in rule to filter on _geo field coordinates.", keyword),
|
||||||
Self::BadGeoLat(lat) => write!(f, "Bad latitude `{}`. Latitude must be contained between -90 and 90 degrees. ", lat),
|
Self::BadGeoLat(lat) => write!(f, "Bad latitude `{}`. Latitude must be contained between -90 and 90 degrees. ", lat),
|
||||||
Self::BadGeoLng(lng) => write!(f, "Bad longitude `{}`. Longitude must be contained between -180 and 180 degrees. ", lng),
|
Self::BadGeoLng(lng) => write!(f, "Bad longitude `{}`. Longitude must be contained between -180 and 180 degrees. ", lng),
|
||||||
|
Self::InternalError => write!(f, "Internal error while executing this filter."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -315,9 +317,14 @@ impl<'a> Filter<'a> {
|
|||||||
|
|
||||||
match &self.condition {
|
match &self.condition {
|
||||||
FilterCondition::Condition { fid, op } => {
|
FilterCondition::Condition { fid, op } => {
|
||||||
let filterable_fields = index.fields_ids_map(rtxn)?;
|
let filterable_fields = index.filterable_fields(rtxn)?;
|
||||||
if let Some(fid) = filterable_fields.id(&fid.inner.to_lowercase()) {
|
if filterable_fields.contains(&fid.inner.to_lowercase()) {
|
||||||
|
let field_ids_map = index.fields_ids_map(rtxn)?;
|
||||||
|
if let Some(fid) = field_ids_map.id(fid.inner) {
|
||||||
Self::evaluate_operator(rtxn, index, numbers_db, strings_db, fid, &op)
|
Self::evaluate_operator(rtxn, index, numbers_db, strings_db, fid, &op)
|
||||||
|
} else {
|
||||||
|
return Err(fid.as_external_error(FilterError::InternalError))?;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
match fid.inner {
|
match fid.inner {
|
||||||
attribute @ "_geo" => {
|
attribute @ "_geo" => {
|
||||||
@ -334,8 +341,7 @@ impl<'a> Filter<'a> {
|
|||||||
FilterError::AttributeNotFilterable {
|
FilterError::AttributeNotFilterable {
|
||||||
attribute,
|
attribute,
|
||||||
filterable: filterable_fields
|
filterable: filterable_fields
|
||||||
.iter()
|
.into_iter()
|
||||||
.map(|(_, s)| s)
|
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(" "),
|
.join(" "),
|
||||||
},
|
},
|
||||||
@ -356,8 +362,8 @@ impl<'a> Filter<'a> {
|
|||||||
}
|
}
|
||||||
FilterCondition::Empty => Ok(RoaringBitmap::new()),
|
FilterCondition::Empty => Ok(RoaringBitmap::new()),
|
||||||
FilterCondition::GeoLowerThan { point, radius } => {
|
FilterCondition::GeoLowerThan { point, radius } => {
|
||||||
let filterable_fields = index.fields_ids_map(rtxn)?;
|
let filterable_fields = index.filterable_fields(rtxn)?;
|
||||||
if filterable_fields.id("_geo").is_some() {
|
if filterable_fields.contains("_geo") {
|
||||||
let base_point: [f64; 2] = [point[0].parse()?, point[1].parse()?];
|
let base_point: [f64; 2] = [point[0].parse()?, point[1].parse()?];
|
||||||
if !(-90.0..=90.0).contains(&base_point[0]) {
|
if !(-90.0..=90.0).contains(&base_point[0]) {
|
||||||
return Err(
|
return Err(
|
||||||
@ -387,11 +393,7 @@ impl<'a> Filter<'a> {
|
|||||||
} else {
|
} else {
|
||||||
return Err(point[0].as_external_error(FilterError::AttributeNotFilterable {
|
return Err(point[0].as_external_error(FilterError::AttributeNotFilterable {
|
||||||
attribute: "_geo",
|
attribute: "_geo",
|
||||||
filterable: filterable_fields
|
filterable: filterable_fields.into_iter().collect::<Vec<_>>().join(" "),
|
||||||
.iter()
|
|
||||||
.map(|(_, s)| s)
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(" "),
|
|
||||||
}))?;
|
}))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -487,6 +489,50 @@ mod tests {
|
|||||||
assert_eq!(condition, expected);
|
assert_eq!(condition, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn not_filterable() {
|
||||||
|
let path = tempfile::tempdir().unwrap();
|
||||||
|
let mut options = EnvOpenOptions::new();
|
||||||
|
options.map_size(10 * 1024 * 1024); // 10 MB
|
||||||
|
let index = Index::new(options, &path).unwrap();
|
||||||
|
|
||||||
|
let rtxn = index.read_txn().unwrap();
|
||||||
|
let filter = Filter::from_str("_geoRadius(42, 150, 10)").unwrap();
|
||||||
|
let error = filter.evaluate(&rtxn, &index).unwrap_err();
|
||||||
|
assert!(error.to_string().starts_with(
|
||||||
|
"Attribute `_geo` is not filterable. Available filterable attributes are: ``."
|
||||||
|
));
|
||||||
|
|
||||||
|
let filter = Filter::from_str("dog = \"bernese mountain\"").unwrap();
|
||||||
|
let error = filter.evaluate(&rtxn, &index).unwrap_err();
|
||||||
|
assert!(error.to_string().starts_with(
|
||||||
|
"Attribute `dog` is not filterable. Available filterable attributes are: ``."
|
||||||
|
));
|
||||||
|
drop(rtxn);
|
||||||
|
|
||||||
|
// Set the filterable fields to be the channel.
|
||||||
|
let mut wtxn = index.write_txn().unwrap();
|
||||||
|
let mut builder = Settings::new(&mut wtxn, &index, 0);
|
||||||
|
builder.set_searchable_fields(vec![S("title")]);
|
||||||
|
builder.set_filterable_fields(hashset! { S("title") });
|
||||||
|
builder.execute(|_, _| ()).unwrap();
|
||||||
|
wtxn.commit().unwrap();
|
||||||
|
|
||||||
|
let rtxn = index.read_txn().unwrap();
|
||||||
|
|
||||||
|
let filter = Filter::from_str("_geoRadius(-100, 150, 10)").unwrap();
|
||||||
|
let error = filter.evaluate(&rtxn, &index).unwrap_err();
|
||||||
|
assert!(error.to_string().starts_with(
|
||||||
|
"Attribute `_geo` is not filterable. Available filterable attributes are: `title`."
|
||||||
|
));
|
||||||
|
|
||||||
|
let filter = Filter::from_str("name = 12").unwrap();
|
||||||
|
let error = filter.evaluate(&rtxn, &index).unwrap_err();
|
||||||
|
assert!(error.to_string().starts_with(
|
||||||
|
"Attribute `name` is not filterable. Available filterable attributes are: `title`."
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn geo_radius_error() {
|
fn geo_radius_error() {
|
||||||
let path = tempfile::tempdir().unwrap();
|
let path = tempfile::tempdir().unwrap();
|
||||||
|
Loading…
Reference in New Issue
Block a user