Skip to content
This repository was archived by the owner on Jun 11, 2024. It is now read-only.

Commit b958ea6

Browse files
authored
Merge pull request #61 from Qwant/index-cuisine
Add 'cuisine' tag values in 'poi_type.name' used for filtered queries
2 parents bc72e51 + d7ffc26 commit b958ea6

File tree

3 files changed

+62
-20
lines changed

3 files changed

+62
-20
lines changed

src/pois.rs

+50-17
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::addresses::find_address;
22
use crate::addresses::iter_admins;
33
use crate::langs::COUNTRIES_LANGS;
44
use crate::lazy_es::LazyEs;
5+
use itertools::Itertools;
56
use mimir::objects::I18nProperties;
67
use mimir::Poi;
78
use mimir::Property;
@@ -16,6 +17,8 @@ use std::collections::HashMap;
1617

1718
use once_cell::sync::Lazy;
1819

20+
const TAGS_TO_INDEX_AS_POI_TYPE_NAME: &[&str] = &["cuisine"];
21+
1922
static NON_SEARCHABLE_ITEMS: Lazy<BTreeSet<(String, String)>> = Lazy::new(|| {
2023
[
2124
/*
@@ -69,9 +72,9 @@ impl IndexedPoi {
6972
let mapping_key: String = row.get("mapping_key");
7073
let class: String = row.get("class");
7174
let subclass = row.get::<_, Option<String>>("subclass").unwrap_or_default();
72-
73-
let poi_type_id: String = format!("class_{}:subclass_{}", class, subclass);
74-
let poi_type_name: String = format!("class_{} subclass_{}", class, subclass);
75+
let tags = row
76+
.get::<_, Option<HashMap<_, _>>>("tags")
77+
.unwrap_or_default();
7578

7679
let weight = row.get::<_, Option<f64>>("weight").unwrap_or(0.);
7780

@@ -94,7 +97,9 @@ impl IndexedPoi {
9497
return None;
9598
}
9699

97-
let row_properties = properties_from_row(&row).unwrap_or_else(|_| vec![]);
100+
let poi_type_id = format!("class_{}:subclass_{}", class, subclass);
101+
let poi_type_text = build_poi_type_text(&class, &subclass, &tags);
102+
let row_properties = properties_from_tags(tags);
98103
let names = build_names(langs, &row_properties);
99104
let properties = build_poi_properties(&row, row_properties);
100105

@@ -107,7 +112,7 @@ impl IndexedPoi {
107112
approx_coord: Some(poi_coord.into()),
108113
poi_type: PoiType {
109114
id: poi_type_id,
110-
name: poi_type_name,
115+
name: poi_type_text,
111116
},
112117
label: "".into(),
113118
properties,
@@ -217,23 +222,51 @@ impl IndexedPoi {
217222
}
218223
}
219224

220-
fn properties_from_row(row: &Row) -> Result<Vec<Property>, String> {
221-
let properties = row
222-
.try_get::<_, Option<HashMap<_, _>>>("tags")
223-
.map_err(|err| {
224-
let id: String = row.get("id");
225-
warn!("Unable to get tags from row '{}': {:?}", id, err);
226-
err.to_string()
227-
})?
228-
.unwrap_or_else(HashMap::new)
229-
.into_iter()
225+
fn properties_from_tags(tags: HashMap<String, Option<String>>) -> Vec<Property> {
226+
tags.into_iter()
230227
.map(|(k, v)| Property {
231228
key: k,
232229
value: v.unwrap_or_else(|| "".to_string()),
233230
})
234-
.collect::<Vec<Property>>();
231+
.collect()
232+
}
233+
234+
fn build_poi_type_text(
235+
class: &str,
236+
subclass: &str,
237+
tags: &HashMap<String, Option<String>>,
238+
) -> String {
239+
/*
240+
To index certain tags (in addition to class and subclass), we use
241+
the field "poi_type.name" in a convoluted way.
242+
In the POI mapping configuration defined in mimirsbrunn, this field in indexed
243+
using a "word" analyzer.
235244
236-
Ok(properties)
245+
So each key/value must be defined as a word in this field, using the following format:
246+
* "class_<class_name>"
247+
* "subclass_<subclass_name>"
248+
* "<tag_key>:<tag_value>" (e.g "cuisine:japanese")
249+
250+
When the tag contains multiple values (separated by ";"), these values are split
251+
and indexed as distinct tag values.
252+
*/
253+
std::array::IntoIter::new([format!("class_{}", class), format!("subclass_{}", subclass)])
254+
.chain(
255+
TAGS_TO_INDEX_AS_POI_TYPE_NAME
256+
.iter()
257+
.map(|tag| {
258+
let values = tags.get(*tag).unwrap_or(&None).clone().unwrap_or_default();
259+
if values.is_empty() {
260+
return vec![];
261+
}
262+
values
263+
.split(';')
264+
.map(|v| format!("{}:{}", tag, v))
265+
.collect::<Vec<_>>()
266+
})
267+
.flatten(),
268+
)
269+
.join(" ")
237270
}
238271

239272
fn build_poi_properties(row: &Row, mut properties: Vec<Property>) -> Vec<Property> {

tests/fafnir_tests/data/data.sql

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ INSERT INTO osm_poi_point (
2323
"name:ru" => "студия океана",
2424
"name:it" => "Oceano Studioso",
2525
"name_int" => "Ocean Studio",
26-
"name:latin" => "Ocean Studio"
26+
"name:latin" => "Ocean Studio",
27+
"cuisine" => "japanese;coffee_shop"
2728
'
2829
),
2930
-- POI located at lon=2, lat=2

tests/fafnir_tests/mod.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,10 @@ pub fn main_test(mut es_wrapper: ElasticSearchWrapper, pg_wrapper: PostgresWrapp
185185
assert_eq!(label_ocean_poi, &"Ocean Studio (bob's town)");
186186
// Test poi_type
187187
let poi_type_ocean_poi = &ocean_poi.poi_type.name;
188-
assert_eq!(poi_type_ocean_poi, &"class_cafe subclass_cafe");
188+
assert_eq!(
189+
poi_type_ocean_poi,
190+
&"class_cafe subclass_cafe cuisine:japanese cuisine:coffee_shop"
191+
);
189192

190193
// Test Properties: the amenity property for this POI should be "cafe"
191194
let properties_ocean_poi = &ocean_poi.properties;
@@ -348,9 +351,14 @@ pub fn main_test(mut es_wrapper: ElasticSearchWrapper, pg_wrapper: PostgresWrapp
348351
// Test existance of water POIs
349352
let res = es_wrapper.search_and_filter("name:(Fontaine-Lavoir Saint-Guimond)", |_| true);
350353
assert_eq!(res.count(), 1);
351-
352354
let res = es_wrapper.search_and_filter("name:(Baie du Mont Saint-Michel)", |_| true);
353355
assert_eq!(res.count(), 1);
356+
357+
// Filter by poi_type.name
358+
let res = es_wrapper.search_and_filter("poi_type.name:(subclass_cafe)", |_| true);
359+
assert_eq!(res.count(), 2);
360+
let res = es_wrapper.search_and_filter("poi_type.name:(cuisine\\:coffee_shop)", |_| true);
361+
assert_eq!(res.count(), 1);
354362
}
355363

356364
pub fn bbox_test(mut es_wrapper: ElasticSearchWrapper, pg_wrapper: PostgresWrapper) {

0 commit comments

Comments
 (0)