meilisearch/meilisearch-http/src/index/mod.rs

193 lines
5.9 KiB
Rust
Raw Normal View History

2021-05-31 22:40:59 +08:00
use std::collections::{BTreeSet, HashSet};
use std::fs::create_dir_all;
use std::marker::PhantomData;
2021-03-04 18:56:32 +08:00
use std::ops::Deref;
2021-05-31 22:40:59 +08:00
use std::path::Path;
use std::sync::Arc;
2021-03-04 18:56:32 +08:00
2021-03-04 22:09:00 +08:00
use anyhow::{bail, Context};
2021-05-27 04:52:06 +08:00
use heed::{EnvOpenOptions, RoTxn};
2021-03-04 21:20:19 +08:00
use milli::obkv_to_json;
use serde_json::{Map, Value};
2021-03-04 21:20:19 +08:00
2021-04-14 23:53:12 +08:00
use crate::helpers::EnvSizer;
2021-03-04 18:56:32 +08:00
pub use search::{SearchQuery, SearchResult, DEFAULT_SEARCH_LIMIT};
2021-05-11 02:22:18 +08:00
use serde::{de::Deserializer, Deserialize};
2021-05-31 22:03:39 +08:00
pub use updates::{Checked, Facets, Settings, Unchecked};
2021-03-04 18:56:32 +08:00
2021-05-27 04:52:06 +08:00
mod dump;
2021-05-31 22:03:39 +08:00
mod search;
2021-05-27 04:52:06 +08:00
pub mod update_handler;
2021-05-31 22:03:39 +08:00
mod updates;
2021-04-01 22:44:42 +08:00
2021-03-04 21:20:19 +08:00
pub type Document = Map<String, Value>;
2021-03-04 18:56:32 +08:00
#[derive(Clone)]
pub struct Index(pub Arc<milli::Index>);
impl Deref for Index {
type Target = milli::Index;
fn deref(&self) -> &Self::Target {
self.0.as_ref()
}
}
2021-03-04 19:38:55 +08:00
2021-05-11 02:22:18 +08:00
pub fn deserialize_some<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
where
T: Deserialize<'de>,
D: Deserializer<'de>,
{
Deserialize::deserialize(deserializer).map(Some)
}
2021-03-04 19:38:55 +08:00
impl Index {
2021-05-27 04:52:06 +08:00
pub fn open(path: impl AsRef<Path>, size: usize) -> anyhow::Result<Self> {
2021-05-31 22:40:59 +08:00
create_dir_all(&path)?;
2021-05-27 04:52:06 +08:00
let mut options = EnvOpenOptions::new();
options.map_size(size);
let index = milli::Index::new(options, &path)?;
Ok(Index(Arc::new(index)))
}
2021-05-10 23:30:09 +08:00
pub fn settings(&self) -> anyhow::Result<Settings<Checked>> {
2021-03-04 19:38:55 +08:00
let txn = self.read_txn()?;
2021-05-25 00:16:35 +08:00
self.settings_txn(&txn)
}
2021-03-04 19:38:55 +08:00
2021-05-25 00:16:35 +08:00
pub fn settings_txn(&self, txn: &RoTxn) -> anyhow::Result<Settings<Checked>> {
2021-03-04 19:38:55 +08:00
let displayed_attributes = self
.displayed_fields(&txn)?
2021-05-11 17:47:04 +08:00
.map(|fields| fields.into_iter().map(String::from).collect());
2021-03-04 19:38:55 +08:00
let searchable_attributes = self
.searchable_fields(&txn)?
2021-05-11 17:47:04 +08:00
.map(|fields| fields.into_iter().map(String::from).collect());
2021-03-04 19:38:55 +08:00
let faceted_attributes = self
.faceted_fields(&txn)?
.into_iter()
.collect();
2021-03-12 05:39:16 +08:00
let criteria = self
.criteria(&txn)?
.into_iter()
.map(|c| c.to_string())
.collect();
let stop_words = self
.stop_words(&txn)?
.map(|stop_words| -> anyhow::Result<BTreeSet<_>> {
Ok(stop_words.stream().into_strs()?.into_iter().collect())
})
.transpose()?
.unwrap_or_else(BTreeSet::new);
2021-06-04 01:36:25 +08:00
let distinct_field = self.distinct_field(&txn)?.map(String::from);
2021-06-14 16:38:56 +08:00
// in milli each word in the synonyms map were split on their separator. Since we lost
// this information we are going to put space between words.
2021-06-03 20:19:56 +08:00
let synonyms = self
.synonyms(&txn)?
.iter()
.map(|(key, values)| {
(
key.join(" "),
values.iter().map(|value| value.join(" ")).collect(),
)
})
.collect();
2021-03-04 19:38:55 +08:00
Ok(Settings {
2021-05-11 17:47:04 +08:00
displayed_attributes: Some(displayed_attributes),
searchable_attributes: Some(searchable_attributes),
filterable_attributes: Some(Some(faceted_attributes)),
2021-03-12 05:39:16 +08:00
ranking_rules: Some(Some(criteria)),
stop_words: Some(Some(stop_words)),
2021-06-04 01:36:25 +08:00
distinct_attribute: Some(distinct_field),
2021-06-03 20:19:56 +08:00
synonyms: Some(Some(synonyms)),
2021-05-10 23:30:09 +08:00
_kind: PhantomData,
2021-03-04 19:38:55 +08:00
})
}
2021-03-04 21:20:19 +08:00
2021-03-16 01:11:10 +08:00
pub fn retrieve_documents<S: AsRef<str>>(
2021-03-04 21:20:19 +08:00
&self,
offset: usize,
limit: usize,
attributes_to_retrieve: Option<Vec<S>>,
2021-03-16 01:11:10 +08:00
) -> anyhow::Result<Vec<Map<String, Value>>> {
2021-03-04 21:20:19 +08:00
let txn = self.read_txn()?;
let fields_ids_map = self.fields_ids_map(&txn)?;
2021-03-16 01:11:10 +08:00
let fields_to_display =
2021-04-19 22:22:41 +08:00
self.fields_to_display(&txn, &attributes_to_retrieve, &fields_ids_map)?;
2021-03-04 21:20:19 +08:00
let iter = self.documents.range(&txn, &(..))?.skip(offset).take(limit);
let mut documents = Vec::new();
for entry in iter {
let (_id, obkv) = entry?;
let object = obkv_to_json(&fields_to_display, &fields_ids_map, obkv)?;
2021-03-04 21:20:19 +08:00
documents.push(object);
}
Ok(documents)
}
2021-03-04 22:09:00 +08:00
pub fn retrieve_document<S: AsRef<str>>(
&self,
doc_id: String,
attributes_to_retrieve: Option<Vec<S>>,
) -> anyhow::Result<Map<String, Value>> {
let txn = self.read_txn()?;
2021-03-04 22:09:00 +08:00
let fields_ids_map = self.fields_ids_map(&txn)?;
2021-03-04 22:09:00 +08:00
2021-03-16 01:11:10 +08:00
let fields_to_display =
2021-04-19 22:22:41 +08:00
self.fields_to_display(&txn, &attributes_to_retrieve, &fields_ids_map)?;
let internal_id = self
.external_documents_ids(&txn)?
.get(doc_id.as_bytes())
.with_context(|| format!("Document with id {} not found", doc_id))?;
let document = self
.documents(&txn, std::iter::once(internal_id))?
.into_iter()
.next()
.map(|(_, d)| d);
match document {
2021-03-16 01:11:10 +08:00
Some(document) => Ok(obkv_to_json(&fields_to_display, &fields_ids_map, document)?),
None => bail!("Document with id {} not found", doc_id),
}
2021-03-04 22:09:00 +08:00
}
pub fn size(&self) -> u64 {
self.env.size()
2021-04-01 22:44:42 +08:00
}
fn fields_to_display<S: AsRef<str>>(
&self,
txn: &heed::RoTxn,
2021-04-19 22:22:41 +08:00
attributes_to_retrieve: &Option<Vec<S>>,
fields_ids_map: &milli::FieldsIdsMap,
) -> anyhow::Result<Vec<u8>> {
let mut displayed_fields_ids = match self.displayed_fields_ids(&txn)? {
Some(ids) => ids.into_iter().collect::<Vec<_>>(),
None => fields_ids_map.iter().map(|(id, _)| id).collect(),
};
let attributes_to_retrieve_ids = match attributes_to_retrieve {
Some(attrs) => attrs
.iter()
.filter_map(|f| fields_ids_map.id(f.as_ref()))
.collect::<HashSet<_>>(),
None => fields_ids_map.iter().map(|(id, _)| id).collect(),
};
displayed_fields_ids.retain(|fid| attributes_to_retrieve_ids.contains(fid));
Ok(displayed_fields_ids)
}
2021-03-04 19:38:55 +08:00
}