Introduce a new facet filters query field

This commit is contained in:
Kerollmops 2021-01-07 10:15:31 +01:00
parent afa86d8a45
commit 33945a3115
No known key found for this signature in database
GPG Key ID: 92ADA4E935E71FA4
5 changed files with 407 additions and 321 deletions

627
http-ui/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -22,6 +22,7 @@ tempfile = "3.1.0"
askama = "0.10.1" askama = "0.10.1"
askama_warp = "0.10.0" askama_warp = "0.10.0"
bytes = "0.5.6" bytes = "0.5.6"
either = "1.6.1"
flate2 = "1.0.19" flate2 = "1.0.19"
futures = "0.3.6" futures = "0.3.6"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }

View File

@ -2,9 +2,10 @@ var request = null;
var timeoutID = null; var timeoutID = null;
var selected_facets = {}; var selected_facets = {};
$('#query, #facet').on('input', function () { $('#query, #filters').on('input', function () {
var query = $('#query').val(); var query = $('#query').val();
var facet = $('#facet').val(); var filters = $('#filters').val();
var facet_filters = selectedFacetsToArray(selected_facets);
var timeoutMs = 100; var timeoutMs = 100;
if (timeoutID !== null) { if (timeoutID !== null) {
@ -17,7 +18,10 @@ $('#query, #facet').on('input', function () {
url: "query", url: "query",
contentType: 'application/json', contentType: 'application/json',
data: JSON.stringify({ data: JSON.stringify({
'query': query, 'facetCondition': facet, "facetDistribution": true 'query': query,
'filters': filters,
'facetFilters': facet_filters,
"facetDistribution": true,
}), }),
contentType: 'application/json', contentType: 'application/json',
success: function (data, textStatus, request) { success: function (data, textStatus, request) {
@ -41,7 +45,20 @@ $('#query, #facet').on('input', function () {
// Create the select element // Create the select element
let select = $(`<select data-facet-name='${facet_name}' multiple size=\"8\"></select>`); let select = $(`<select data-facet-name='${facet_name}' multiple size=\"8\"></select>`);
for (value of data.facets[facet_name]) { let selected_values = selected_facets[facet_name] || [];
// Create the previously selected facets (mark them as selected)
for (value of selected_values) {
let option = $('<option></option>')
.text(value)
.attr('selected', "selected")
.attr('value', value)
.attr('title', value);
select.append(option);
}
// Create the newly discovered facets
let diff = diffArray(data.facets[facet_name], selected_values);
for (value of diff) {
let option = $('<option></option>') let option = $('<option></option>')
.text(value) .text(value)
.attr('value', value) .attr('value', value)
@ -53,7 +70,6 @@ $('#query, #facet').on('input', function () {
$('#facets').append(div); $('#facets').append(div);
} }
for (element of data.documents) { for (element of data.documents) {
const elem = document.createElement('li'); const elem = document.createElement('li');
elem.classList.add("document"); elem.classList.add("document");
@ -87,8 +103,8 @@ $('#query, #facet').on('input', function () {
$('#facets select').on('change', function(e) { $('#facets select').on('change', function(e) {
let facet_name = $(this).attr('data-facet-name'); let facet_name = $(this).attr('data-facet-name');
selected_facets[facet_name] = $(this).val(); selected_facets[facet_name] = $(this).val();
$('#query').trigger('input');
}); });
}, },
beforeSend: function () { beforeSend: function () {
if (request !== null) { if (request !== null) {
@ -100,6 +116,25 @@ $('#query, #facet').on('input', function () {
}, timeoutMs); }, timeoutMs);
}); });
function diffArray(arr1, arr2) {
return arr1.concat(arr2).filter(function (val) {
if (!(arr1.includes(val) && arr2.includes(val)))
return val;
});
}
function selectedFacetsToArray(facets_obj) {
var array = [];
for (const facet_name in facets_obj) {
var subarray = [];
for (const facet_value of facets_obj[facet_name]) {
subarray.push(`${facet_name}:${facet_value}`);
}
array.push(subarray);
}
return array;
}
// Make the number of document a little bit prettier // Make the number of document a little bit prettier
$('#docs-count').text(function(index, text) { $('#docs-count').text(function(index, text) {
return parseInt(text).toLocaleString() return parseInt(text).toLocaleString()

View File

@ -11,6 +11,7 @@ use std::{mem, io};
use askama_warp::Template; use askama_warp::Template;
use byte_unit::Byte; use byte_unit::Byte;
use either::Either;
use flate2::read::GzDecoder; use flate2::read::GzDecoder;
use futures::stream; use futures::stream;
use futures::{FutureExt, StreamExt}; use futures::{FutureExt, StreamExt};
@ -620,12 +621,29 @@ async fn main() -> anyhow::Result<()> {
.body(include_str!("../public/logo-black.svg")) .body(include_str!("../public/logo-black.svg"))
); );
#[derive(Debug, Deserialize)]
#[serde(untagged)]
enum UntaggedEither<L, R> {
Left(L),
Right(R),
}
impl<L, R> From<UntaggedEither<L, R>> for Either<L, R> {
fn from(value: UntaggedEither<L, R>) -> Either<L, R> {
match value {
UntaggedEither::Left(left) => Either::Left(left),
UntaggedEither::Right(right) => Either::Right(right),
}
}
}
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
struct QueryBody { struct QueryBody {
query: Option<String>, query: Option<String>,
facet_condition: Option<String>, filters: Option<String>,
facet_filters: Option<Vec<UntaggedEither<Vec<String>, String>>>,
facet_distribution: Option<bool>, facet_distribution: Option<bool>,
} }
@ -651,12 +669,33 @@ async fn main() -> anyhow::Result<()> {
if let Some(query) = query.query { if let Some(query) = query.query {
search.query(query); search.query(query);
} }
if let Some(condition) = query.facet_condition {
if !condition.trim().is_empty() { let filters = match query.filters {
let condition = FacetCondition::from_str(&rtxn, &index, &condition).unwrap(); Some(condition) if !condition.trim().is_empty() => {
Some(FacetCondition::from_str(&rtxn, &index, &condition).unwrap())
},
_otherwise => None,
};
let facet_filters = match query.facet_filters {
Some(array) => {
let eithers = array.into_iter().map(Into::into);
FacetCondition::from_array(&rtxn, &index, eithers).unwrap()
},
_otherwise => None,
};
let condition = match (filters, facet_filters) {
(Some(filters), Some(facet_filters)) => {
Some(FacetCondition::And(Box::new(filters), Box::new(facet_filters)))
},
(Some(condition), None) | (None, Some(condition)) => Some(condition),
_otherwise => None,
};
if let Some(condition) = condition {
search.facet_condition(condition); search.facet_condition(condition);
} }
}
let SearchResult { found_words, candidates, documents_ids } = search.execute().unwrap(); let SearchResult { found_words, candidates, documents_ids } = search.execute().unwrap();

View File

@ -56,7 +56,7 @@
<div class="level-item"> <div class="level-item">
<div class="field has-addons has-addons-right"> <div class="field has-addons has-addons-right">
<input id="query" class="input" type="text" autofocus placeholder="e.g. George Clooney"> <input id="query" class="input" type="text" autofocus placeholder="e.g. George Clooney">
<input id="facet" class="input" type="text" placeholder="facet filter like released >= 1577836800"> <input id="filters" class="input" type="text" placeholder="filters like released >= 1577836800">
</div> </div>
</div> </div>
<div class="level-item"></div> <div class="level-item"></div>