179: Enable filter paramater during search r=MarinPostma a=MarinPostma

This pr makes the necessary changes to transplant in accordance with the specification on filters.

More precisely, it:
- Removes the `filters` parameter
- Renames `facetFilters` to `filter`
- Allows either a string or an array to be passed to the filter param.

It doesn't allow the mixed syntax, that needs to be handled by milli.

close #81
close #140


Co-authored-by: Marin Postma <postma.marin@protonmail.com>
This commit is contained in:
bors[bot] 2021-06-14 08:11:30 +00:00 committed by GitHub
commit d765397c82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 43 additions and 41 deletions

View File

@ -33,9 +33,8 @@ pub struct SearchQuery {
pub attributes_to_crop: Option<HashSet<String>>, pub attributes_to_crop: Option<HashSet<String>>,
pub crop_length: Option<usize>, pub crop_length: Option<usize>,
pub attributes_to_highlight: Option<HashSet<String>>, pub attributes_to_highlight: Option<HashSet<String>>,
pub filters: Option<String>,
pub matches: Option<bool>, pub matches: Option<bool>,
pub facet_filters: Option<Value>, pub filter: Option<Value>,
pub facet_distributions: Option<Vec<String>>, pub facet_distributions: Option<Vec<String>>,
} }
@ -75,8 +74,8 @@ impl Index {
search.limit(query.limit); search.limit(query.limit);
search.offset(query.offset.unwrap_or_default()); search.offset(query.offset.unwrap_or_default());
if let Some(ref facets) = query.facet_filters { if let Some(ref filter) = query.filter {
if let Some(facets) = parse_facets(facets, self, &rtxn)? { if let Some(facets) = parse_facets(filter, self, &rtxn)? {
search.facet_condition(facets); search.facet_condition(facets);
} }
} }
@ -277,35 +276,6 @@ impl Matcher for MatchingWords {
} }
} }
fn parse_facets_array(
txn: &RoTxn,
index: &Index,
arr: &[Value],
) -> anyhow::Result<Option<FacetCondition>> {
let mut ands = Vec::new();
for value in arr {
match value {
Value::String(s) => ands.push(Either::Right(s.clone())),
Value::Array(arr) => {
let mut ors = Vec::new();
for value in arr {
match value {
Value::String(s) => ors.push(s.clone()),
v => bail!("Invalid facet expression, expected String, found: {:?}", v),
}
}
ands.push(Either::Left(ors));
}
v => bail!(
"Invalid facet expression, expected String or [String], found: {:?}",
v
),
}
}
FacetCondition::from_array(txn, &index.0, ands)
}
struct Highlighter<'a, A> { struct Highlighter<'a, A> {
analyzer: Analyzer<'a, A>, analyzer: Analyzer<'a, A>,
marks: (String, String), marks: (String, String),
@ -367,13 +337,41 @@ fn parse_facets(
txn: &RoTxn, txn: &RoTxn,
) -> anyhow::Result<Option<FacetCondition>> { ) -> anyhow::Result<Option<FacetCondition>> {
match facets { match facets {
// Disabled for now Value::String(expr) => Ok(Some(FacetCondition::from_str(txn, index, expr)?)),
//Value::String(expr) => Ok(Some(FacetCondition::from_str(txn, index, expr)?)),
Value::Array(arr) => parse_facets_array(txn, index, arr), Value::Array(arr) => parse_facets_array(txn, index, arr),
v => bail!("Invalid facet expression, expected Array, found: {:?}", v), v => bail!("Invalid facet expression, expected Array, found: {:?}", v),
} }
} }
fn parse_facets_array(
txn: &RoTxn,
index: &Index,
arr: &[Value],
) -> anyhow::Result<Option<FacetCondition>> {
let mut ands = Vec::new();
for value in arr {
match value {
Value::String(s) => ands.push(Either::Right(s.clone())),
Value::Array(arr) => {
let mut ors = Vec::new();
for value in arr {
match value {
Value::String(s) => ors.push(s.clone()),
v => bail!("Invalid facet expression, expected String, found: {:?}", v),
}
}
ands.push(Either::Left(ors));
}
v => bail!(
"Invalid facet expression, expected String or [String], found: {:?}",
v
),
}
}
FacetCondition::from_array(txn, &index.0, ands)
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use std::iter::FromIterator; use std::iter::FromIterator;

View File

@ -2,6 +2,7 @@ use std::collections::HashSet;
use std::convert::{TryFrom, TryInto}; use std::convert::{TryFrom, TryInto};
use actix_web::{get, post, web, HttpResponse}; use actix_web::{get, post, web, HttpResponse};
use serde_json::Value;
use serde::Deserialize; use serde::Deserialize;
use crate::error::ResponseError; use crate::error::ResponseError;
@ -24,9 +25,8 @@ pub struct SearchQueryGet {
attributes_to_crop: Option<String>, attributes_to_crop: Option<String>,
crop_length: Option<usize>, crop_length: Option<usize>,
attributes_to_highlight: Option<String>, attributes_to_highlight: Option<String>,
filters: Option<String>, filter: Option<String>,
matches: Option<bool>, matches: Option<bool>,
facet_filters: Option<String>,
facet_distributions: Option<String>, facet_distributions: Option<String>,
} }
@ -50,8 +50,13 @@ impl TryFrom<SearchQueryGet> for SearchQuery {
.facet_distributions .facet_distributions
.map(|attrs| attrs.split(',').map(String::from).collect::<Vec<_>>()); .map(|attrs| attrs.split(',').map(String::from).collect::<Vec<_>>());
let facet_filters = match other.facet_filters { let filter = match other.filter {
Some(ref f) => Some(serde_json::from_str(f)?), Some(f) => {
match serde_json::from_str(&f) {
Ok(v) => Some(v),
_ => Some(Value::String(f)),
}
},
None => None, None => None,
}; };
@ -63,9 +68,8 @@ impl TryFrom<SearchQueryGet> for SearchQuery {
attributes_to_crop, attributes_to_crop,
crop_length: other.crop_length, crop_length: other.crop_length,
attributes_to_highlight, attributes_to_highlight,
filters: other.filters, filter,
matches: other.matches, matches: other.matches,
facet_filters,
facet_distributions, facet_distributions,
}) })
} }