es 7.0 自定义字段以及painless脚本计算逻辑

1,369 阅读4分钟

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最近生产环境碰到的问题和调优,希望有时间吧啊。发现很多时候自己看的东西,碰到的问题不记录真的容易忘记,也不利于成长。大家都加油啊