我有下一个模型结构:
Product:
name: char
Shop:
location: geo_point
ShopProduct:
shop: ForeignKey(Shop)
product: ForeignKey(Product)
price: double
我需要Product
使用ElasticSearch(v5.2)实现搜索。因此,如果用户输入某个产品名称,他将在结果中收到产品名称,最近位置以及最低和最高价格。另外,我需要按名称,位置和价格排序。
我有两个问题:
1。我应该使用哪种映射结构用于ElasticSearch索引,以按地点/价格排序按产品进行搜索?
目前,我有两个指数,第一个是产品,第二个是商店。产品索引具有“嵌套”数据类型到商店位置。我已添加它,因为我需要按位置和价格实现排序功能。我觉得这不是一个好主意,但我不确定应该使用哪种数据结构来实现排序。此外,我正在考虑亲子关系,但我认为它不适合我的数据 - 在文档中提到它应该用于一些父对象和许多孩子。
# Product Index
"mappings": {
"product": {
"properties": {
"name": {"type": "string"}
"locations": {
"type": "nested",
"properties": {
"location": {"type": "geo_point"},
"price": {"type": "float"}
}
}
}
}
}
# Shop Index
"mappings": {
"shop": {
"properties": {
"location": {"type": "geo_point"},
"shop_products": {
"type": "nested",
"properties": {
"product_id": {"type": "long"},
"product_name": {"type": "string"},
"price": {"type": "float"}
}
},
}
}
}
2。如何获得每种产品的最近位置和最低/最高价格?
我尝试使用带有这样的脚本的script_fields来计算它,但后来注意到ElasticSearch不允许我访问嵌套对象。所以,这个脚本不起作用。
"script_fields": {
"locations": {
"script": {
"lang": "painless",
"params": {
'lat': 50,
'lon': -120
},
"inline": """
def locations = params._source.locations; // I've also try doc['locations.location'].value
if (locations.length > 0) {
distance = locations[0].location.planeDistanceWithDefault(params.lat, params.lon, 0)
for (int i = 1; i < locations.length; ++i) {
if (distance > locations[i].location.planeDistanceWithDefault(params.lat, params.lon, 0)) {
distance = locations[i].location.planeDistanceWithDefault(params.lat, params.lon, 0)
}
}
}
return distance;
"""
}
}
}
然后,我尝试使用聚合来计算最低/最高价格和最近的位置。聚合对我有用,但ElasticSearch对aggs没有任何分页,并且有一个issue。
"aggs": {
"product": {
"terms": {
"field": "name"
},
"aggs": {
"prices": {
"nested": {
"path": "locations"
},
"aggs": {
"price": {
"stat": {
"field": "locations.price"
}
},
"min_distance": {
"min": {
"script": {
"lang": "painless",
"inline": """
if (params.lat != 0 && params.lon != 0){
def distance = doc['locations.location'].planeDistanceWithDefault(params.lat, params.lon, 0);
if (distance !=0){
return distance;
}
}
""",
"params": {
'lat': 50,
'lon': -120
}
}
}
}
}}}}}
在我的例子中,每个产品可以有大约30个商店出售它。所以,我不想在结果中返回所有可用的位置,只是最近或在交付区域。这就是为什么我要单独查询以获取每个产品的位置。
提前谢谢。