es 7.0 自定义字段以及painless脚本计算逻辑
首先这里建议大家安装elk,也就是elastcisearch7.0+logstash+kibana。通过可视化的工具能够很好地方便我们进行调试。 这里粘贴一个很好地教程,转载如下: 搭建elk环境
使用localhost:5601登录kibana系统后,我们进入Dev tools。
使用以下命令
- 创建索引
PUT /es_price_index_20 - 创建索引映射(文档结构) es7之后删除了type的概念。这里我们创建一个sku的价格模型。单个sku对于不同采购商,不同的协议,不同的售卖地点可能有不同的价格。这些价格记录在priceList字段中。另外,对于没有签订协议的商品,我们要求走供应商的发布价,取price字段。
POST es_price_index_20/_mapping
{
"properties": {
"price":{
"type":"double"
},
"skuId": {
"type": "long"
},
"skuName": {
"type": "text"
},
"priceList": {
"type": "nested",
"properties": {
"location": {
"type": "long"
},
"price": {
"type": "double"
},
"aggrement": {
"type": "long"
},
"buyerCode":{
"type":"long"
}
}
}
}
}
创建完mapping后,我们可以使用GET /es_price_index_20/查看我们刚刚建立的mapping结构
- 灌数据
#灌入数据,insert
POST /es_price_index_20/_doc/_bulk
{"index":{"_id":1}}
{"skuId":1001,"skuName":"小米手机","priceList":[{"location":[1,2,3],"price":20,"aggrement":1,"buyerCode":1},{"location":[2,3],"price":9,"aggrement":2,"buyerCode":1},{"location":[4],"price":50,"aggrement":3,"buyerCode":3}],"price":10}
{"index":{"_id":2}}
{"skuId":1002,"skuName":"小手机","priceList":[{"location":[2,3,4],"price":19,"aggrement":1,"buyerCode":1},{"location":[1],"price":26,"aggrement":1,"buyerCode":3},{"location":[1,2,3],"price":111,"aggrement":1,"buyerCode":2},{"location":[3],"price":20,"aggrement":3,"buyerCode":1}],"price":20}
{"index":{"_id":3}}
{"skuId":1003,"skuName":"超级小小小手机","priceList":[{"location":[1,2,3],"price":20,"aggrement":1,"buyerCode":1},{"location":[2,3],"price":25,"aggrement":1,"buyerCode":2},{"location":[2],"price":1220,"aggrement":1,"buyerCode":3},{"location":[1,3,5],"price":10,"aggrement":3,"buyerCode":4}],"price":25}
{"index":{"_id":4}}
{"skuId":1004,"skuName":"超级大大大手机","priceList":[{"location":[1,2,3],"price":20,"aggrement":1,"buyerCode":1},{"location":[1,4],"price":25,"aggrement":1,"buyerCode":1},{"location":[4,2],"price":1220,"aggrement":1,"buyerCode":2},{"location":[1,4],"price":10,"aggrement":5,"buyerCode":3}],"price":55}
接着我们可以使用POST /es_price_index_20/_search查询下我们刚才灌入的数据,总共命中四条数据
- 前面提到过,对于指定某个采购商,某个地点,我们要求取所有协议里的最低价(如果没有协议,那么取商品本身的价格),现在我们就这个需求对指定buyerCode=4,location=1的采购商和地点取协议最低价.
注意这个价格可能会实时变化,因此最开始考虑将这个价格存储起来的想法不太合适 如下所示,我们使用es提供的script_fields特性自定义一个新的字段,只在查询的时候返回,es不真正存储(可以理解为计算结果的暂存)。
另外,我们使用painless脚本(这个是es官方推荐的)实现对priceList的遍历计算最低协议价与price比对得出最终的价格。根据最终价格,还可以进行排序,只需要在sort中加入script脚本即可
#搜索
POST /es_price_index_20/_search
{
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "手机",
"fields": ["skuName"]
}
}
]
}
},
"script_fields": {
"show_prices": {
"script": {
"params": {
"location":1,
"buyerCode":4
},
"source": "def buyerPriceList = params._source.priceList.findAll(buyerLocation -> buyerLocation.buyerCode == params.buyerCode);double min = params._source.price; for(item in buyerPriceList){for( int i=0;i<item.location.length;i++){if(item.location[i]==params.location){if(min>item.price){min =item.price}}}} return min;"
}
}},
"sort":{
"_script":{
"script":{
"params": {
"location":1,
"buyerCode":4
},
"inline": "def buyerPriceList = params._source.priceList.findAll(buyerLocation -> buyerLocation.buyerCode == params.buyerCode);double min = params._source.price; for(item in buyerPriceList){for( int i=0;i<item.location.length;i++){if(item.location[i]==params.location){if(min>item.price){min =item.price}}}} return min;"
},
"type":"number",
"order": "desc"
}
},
"_source": ["skuName","price"],
"from": 0,
"size": 4
}
最终搜索效果如下所示
- 附言 如果es商城搜索页面有collapse同类商品折叠情况。比如同一种商品(spu)不让全部显示在搜索页面了,只展示其中一种sku,剩余几种折叠起来。如果要展示最低价,那么也可以参考如下进行使用。这样就能分别计算spu底下所有sku的价格了
{
"collapse": {
"field": "itemId",
"inner_hits": {
"name": "item_sku",
"ignore_unmapped": false,
"from": 0,
"size": 100,
"script_fields": {
"show_prices": {
"script": {
"params": {
"partACode": "E00000101",
"location": 1
},
"source": "def buyerPriceList = params._source.sellPriceList.findAll(buyerLocation -> buyerLocation.partACode == params.partACode);double min = params._source.sellPrice; for(item in buyerPriceList){for( int i=0;i<item.provinceCodeList.length;i++){if(item.provinceCodeList[i]==params.location){if(min>item.agreementPrice){min =item.agreementPrice}}}} return min;"
}
}
},
"_source": {
"includes": ["*"],
"excludes": []
},
"sort": {
"_script": {
"script": {
"params": {
"partACode": "E00000101",
"location": 1
},
"inline": "def buyerPriceList = params._source.sellPriceList.findAll(buyerLocation -> buyerLocation.partACode == params.partACode);double min = params._source.sellPrice; for(item in buyerPriceList){for( int i=0;i<item.provinceCodeList.length;i++){if(item.provinceCodeList[i]==params.location){if(min>item.agreementPrice){min =item.agreementPrice}}}} return min;"
},
"type": "number",
"order": "desc"
}
}
}
}
}
- 闲聊
下一篇有时间总结下es最近生产环境碰到的问题和调优,希望有时间吧啊。发现很多时候自己看的东西,碰到的问题不记录真的容易忘记,也不利于成长。大家都加油啊