业务背景
在 TO B 行业,对商品的搜索展示,是有一定业务要求的,例如:存在合作关系的买家和供应商才能看到供应商店铺的商品,不存在合作关系的买家则不展示商品。另外,有些商品对客户甲展示一种价格,对客户乙则展示另外一种价格,从而区分不同的会员、分组对商品价格的区别。
一句话总结:TO B 行业的商品销售具有一定封闭性、特殊性。后续例子均在此背景下展开描述,以方便大家更加贴近业务场景来熟悉 Elasticsearch 对文档、索引、查询的一系列操作。
本文采用 IK 做分词器,下载的 IK 分词器版本必须和 Elasticsearch 版本一致
IK下载地址:https://github.com/medcl/elasticsearch-analysis-ik/releases
- 在 Elasticsearch 的安装目录的 Plugins 目录下新建 IK 文件夹,然后将下载的 IK 安装包解压到此目录下。
- 重启 ES 即可。
定义 Mapping
商品字段描述如下:
- goodsName: 商品名称
- skuCode:商品 sku 编码
- brandName:商品品牌名称
- channelType:渠道类型
- shopCode: 店铺编码
- publicPrice:售卖价格(基础价,对所有人开放价格)
- closeUserCode:封闭会员编码
- groupPrice:分组价格,其中使用嵌套类型存储,包括: 分组价格、 分组级别
定义商品 Mapping
PUTmy_goods{ "settings": { "index": { "number_of_shards": 1, "number_of_replicas": 1 } }, "mappings": { "properties": { "goodsName": { "type": "text", "analyzer": "ik_smart" }, "skuCode": { "type": "keyword" }, "brandName": { "type": "keyword" }, "channelType": { "type": "keyword" }, "shopCode": { "type": "keyword" }, "publicPrice": { "type": "float" }, "closeUserCode": { "type": "text", "analyzer": "standard" }, "boostValue": { "type": "keyword" }, "groupPrice": { "type": "nested", "properties": { "boxLevelPrice": { "type": "float" }, "level": { "type": "text" } } } } } }
Document APIs
主要涉及以下几个核心功能
Index
对文档的新增操作支持以下类型
PUT /<target>/_doc/<_id> POST /<target>/_doc/ PUT /<target>/_create/<_id> POST /<target>/_create/<_id>
以 POST //_create/<_id>为例,以下将创建文档 ID 为 1 的商品信息
POST /my_goods/_create/1
{
"goodsName":"苹果 51英寸 4K超高清",
"skuCode":"skuCode1",
"brandName":"苹果",
"closeUserCode":[
"0"
],
"channelType":"cloudPlatform",
"shopCode":"sc00001",
"publicPrice":"8188.88",
"groupPrice":null,
"boxPrice":null,
"boostValue":1.8
}
Bulk
Elasticsearch 支持批量插入,_bulk 批量导入
POSTmy_goods/_bulk{"index":{"_id":1}} {"goodsName":"苹果 51英寸 4K超高清","skuCode":"skuCode1","brandName":"苹果","closeUserCode":["0"],"channelType":"cloudPlatform","shopCode":"sc00001","publicPrice":"8188.88","groupPrice":null,"boxPrice":null,"boostValue":1.8} {"index":{"_id":2}} {"goodsName":"苹果 55英寸 3K超高清","skuCode":"skuCode2","brandName":"苹果","closeUserCode":["0"],"channelType":"cloudPlatform","shopCode":"sc00002","publicPrice":"6188.88","groupPrice":null,"boxPrice":null,"boostValue":1.0} {"index":{"_id":3}} {"goodsName":"苹果UA55RU7520JXXZ 53英寸 4K高清","skuCode":"skuCode3","brandName":"美国苹果","closeUserCode":["0"],"channelType":"cloudPlatform","shopCode":"sc00001","publicPrice":"8388.88","groupPrice":null,"boxPrice":[{"boxType":"box1","boxUserCode":["htd003","uc004"],"boxPriceDetail":4388.88},{"boxType":"box2","boxUserCode":["uc005","uc0010"],"boxPriceDetail":5388.88}],"boostValue":1.2} {"index":{"_id":4}} {"goodsName":"山东苹果UA55RU7520JXXZ 苹果54英寸 5K超高清","skuCode":"skuCode4","brandName":"山东苹果","closeUserCode":["uc001","uc002","uc003"],"channelType":"cloudPlatform","shopCode":"sc00001","publicPrice":"8488.88","groupPrice":[{"level":"level1","boxLevelPrice":"2488.88"},{"level":"level2","boxLevelPrice":"3488.88"}],"boxPrice":[{"boxType":"box1","boxUserCode":["uc004","uc005","uc006","uc001"],"boxPriceDetail":4488.88},{"boxType":"box2","boxUserCode":["htd007","htd008","htd009","uc0010"],"boxPriceDetail":5488.88}],"boostValue":1.2} {"index":{"_id":5}} {"goodsName":"苹果UA55R苹果U7苹果520JXXZ 55英寸 5K超高清","skuCode":"skuCode5","brandName":"三星苹果","closeUserCode":["uc001","uc002","uc003"],"channelType":"cloudPlatform","shopCode":"sc00001","publicPrice":"8488.88","groupPrice":[{"level":"level1","boxLevelPrice":"2500"},{"level":"level2","boxLevelPrice":"3500"}],"boxPrice":[{"boxType":"box1","boxUserCode":["uc004","uc005","uc006","uc001"],"boxPriceDetail":3588.88},{"boxType":"box2","boxUserCode":["htd007","htd008","htd009","uc0010"],"boxPriceDetail":5588.88}],"boostValue":1.2} {"index":{"_id":6}} {"goodsName":"三星UA55RU7520JXXZ 51英寸 4K超高清","skuCode":"skuCode1","brandName":"三星","closeUserCode":["0"],"channelType":"cmccPlatform","shopCode":"sc00001","publicPrice":"8188.88","groupPrice":null,"boxPrice":null,"boostValue":1.2} {"index":{"_id":7}} {"goodsName":"三星UA55RU7520JXXZ 52英寸 4K超高清","skuCode":"skuCode2","brandName":"三星","closeUserCode":["0"],"channelType":"cmccPlatform","shopCode":"sc00001","publicPrice":"8288.88","groupPrice":null,"boxPrice":[{"boxType":"box1","boxUserCode":["htd002"],"boxPriceDetail":4288.88}],"boostValue":1.2} {"index":{"_id":8}} {"goodsName":"三星UA55RU7520JXXZ 52英寸 4K超高清","skuCode":"skuCode2","brandName":"三星","closeUserCode":["uc0022"],"channelType":"cloudPlatform","shopCode":"sc00001","publicPrice":"8288.88","groupPrice":null,"boxPrice":[{"boxType":"box1","boxUserCode":["uc0022"],"boxPriceDetail":4288.88}],"boostValue":1.2} {"index":{"_id":9}} {"goodsName":"三星UA55RU7520JXXZ 52英寸 4K超高清","skuCode":"skuCode2","brandName":"三星","closeUserCode":["uc0022"],"channelType":"cloudPlatform","shopCode":"sc00001","publicPrice":"8288.88","groupPrice":null,"boxPrice":[{"boxType":"box1","boxUserCode":["uc0022"],"boxPriceDetail":4288.88}],"boostValue":1.2} {"index":{"_id":10}} {"goodsName":"三星UA55RU7520JXXZ 52英寸 4K超高清","skuCode":"skuCode2","brandName":"三星","closeUserCode":["uc0022"],"channelType":"cloudPlatform","shopCode":"sc00001","publicPrice":"8288.88","groupPrice":null,"boxPrice":[{"boxType":"box1","boxUserCode":["uc0022"],"boxPriceDetail":4288.88}],"boostValue":1.8}
Delete
对文档的删除操作支持以下类型
DELETE/<index>/_doc/<_id>
删除文档 ID 为 2 的数据:
DELETE/my_goods/_doc/2
Delete
对文档的删除操作支持以下类型
DELETE /<index>/_doc/<_id>
删除文档 ID 为 2 的数据:
DELETE /my_goods/_doc/2
Delete by query
另外,删除操作支持带多种条件的删除,可以使用 _delete_by_query
如下操纵,将删除店铺编码为 sc00002 的所有商品。
POST/my_goods/_delete_by_query{ "query": { "match": { "shopCode": "sc00002" } } }
Update
对文档的修改操作支持以下类型
POST /<index>/_update/<_id>
修改文档 ID 为1的文档信息
新增字段
POST/my_goods/_update/1{ "doc": { "shopName": "小王店铺" } }
修改店铺名称为:“张三店铺”
POST/my_goods/_update/1{ "doc": { "shopName": "张三店铺" } }
{ "goodsName" : "苹果 51英寸 4K超高清", "skuCode" : "skuCode1", "brandName" : "苹果", "closeUserCode" : [ "0" ], "channelType" : "cloudPlatform", "shopCode" : "sc00001", "publicPrice" : "8188.88", "groupPrice" : null, "boxPrice" : null, "boostValue" : 1.8, "shopName" : "张三店铺"}
另外还可以使用 PUT 进行修改,只不过需要罗列所有字段
PUTmy_goods/_doc/10{ "goodsName": "三星UA55RU7520JXXZ 52英寸 4K超高清", "skuCode": "skuCode10", "brandName": "三星", "closeUserCode": [ "uc0022" ], "channelType": "cloudPlatform", "shopCode": "sc00001", "publicPrice": "8288.88", "groupPrice": null, "boxPrice": [ { "boxType": "box1", "boxUserCode": [ "uc0022" ], "boxPriceDetail": 4288.88 } ], "boostValue": 1.8}
用脚本同样能实现更新操作
POSTmy_goods/_update/10{ "script": { "source": "ctx._source.city=params.channelType", "lang": "painless", "params": { "channelType": "cloudPlatform1" } } }
Update by query
更新操作还可以使用 _update_by_query API,当店铺编码为 sc00002 时修改 publicPrice 为 5888.00 元。
插入文档 ID 为 2 的店铺商品信息
POST/my_goods/_create/2{ "goodsName": "苹果 55英寸 3K超高清", "skuCode": "skuCode2", "brandName": "苹果", "closeUserCode": [ "0" ], "channelType": "cloudPlatform", "shopCode": "sc00002", "publicPrice": "6188.88", "groupPrice": null, "boxPrice": null, "boostValue": 1}
此时查询返回
{ "goodsName" : "苹果 55英寸 3K超高清", "skuCode" : "skuCode2", "brandName" : "苹果", "closeUserCode" : [ "0" ], "channelType" : "cloudPlatform", "shopCode" : "sc00002", "publicPrice" : "6188.88", "groupPrice" : null, "boxPrice" : null, "boostValue" : 1.0}
更新当店铺编码为 sc00002 时修改 publicPrice 为 5888.00 元
POST/my_goods/_update_by_query{ "script": { "source": "ctx._source.publicPrice=5888.00", "lang": "painless" }, "query": { "term": { "shopCode": "sc00002" } } }
再次查询结果
GET/my_goods/_source/2
{ "shopCode" : "sc00002", "brandName" : "苹果", "closeUserCode" : [ "0" ], "groupPrice" : null, "boxPrice" : null, "channelType" : "cloudPlatform", "boostValue" : 1.0, "publicPrice" : 5888.0, "goodsName" : "苹果 55英寸 3K超高清", "skuCode" : "skuCode2"}
Reindex
当有业务需要重建索引时需要用到 _reindex API。
索引的来源和目的地,必须是已经存在的 index、index alias 或者 data stream。
你可以简单的将索引 A reindex 到索引 B,当然也可以带条件的 reindex 到索引 B。
如下所示,将 skuCode=skuCode2 的商品信息 reindex 到索引 my_goods_new 中
POST_reindex{ "source": { "index": "my_goods", "query": { "match": { "skuCode": "skuCode2" } } }, "dest": { "index": "my_goods_new" } }
查询 my_goods_new 索引数据
GETmy_goods_new/_search/
{ "took" : 5, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 4, "relation" : "eq" }, "max_score" : 1.0, "hits" : [ { "_index" : "my_goods_new", "_type" : "_doc", "_id" : "7", "_score" : 1.0, "_source" : { "goodsName" : "三星UA55RU7520JXXZ 52英寸 4K超高清", "skuCode" : "skuCode2", "brandName" : "三星", "closeUserCode" : [ "0" ], "channelType" : "cmccPlatform", "shopCode" : "sc00001", "publicPrice" : "8288.88", "groupPrice" : null, "boxPrice" : [ { "boxType" : "box1", "boxUserCode" : [ "htd002" ], "boxPriceDetail" : 4288.88 } ], "boostValue" : 1.2 } }, { "_index" : "my_goods_new", "_type" : "_doc", "_id" : "8", "_score" : 1.0, "_source" : { "goodsName" : "三星UA55RU7520JXXZ 52英寸 4K超高清", "skuCode" : "skuCode2", "brandName" : "三星", "closeUserCode" : [ "uc0022" ], "channelType" : "cloudPlatform", "shopCode" : "sc00001", "publicPrice" : "8288.88", "groupPrice" : null, "boxPrice" : [ { "boxType" : "box1", "boxUserCode" : [ "uc0022" ], "boxPriceDetail" : 4288.88 } ], "boostValue" : 1.2 } }, { "_index" : "my_goods_new", "_type" : "_doc", "_id" : "9", "_score" : 1.0, "_source" : { "goodsName" : "三星UA55RU7520JXXZ 52英寸 4K超高清", "skuCode" : "skuCode2", "brandName" : "三星", "closeUserCode" : [ "uc0022" ], "channelType" : "cloudPlatform", "shopCode" : "sc00001", "publicPrice" : "8288.88", "groupPrice" : null, "boxPrice" : [ { "boxType" : "box1", "boxUserCode" : [ "uc0022" ], "boxPriceDetail" : 4288.88 } ], "boostValue" : 1.2 } }, { "_index" : "my_goods_new", "_type" : "_doc", "_id" : "10", "_score" : 1.0, "_source" : { "goodsName" : "三星UA55RU7520JXXZ 52英寸 4K超高清", "skuCode" : "skuCode2", "brandName" : "三星", "closeUserCode" : [ "uc0022" ], "channelType" : "cloudPlatform", "shopCode" : "sc00001", "publicPrice" : "8288.88", "groupPrice" : null, "boxPrice" : [ { "boxType" : "box1", "boxUserCode" : [ "uc0022" ], "boxPriceDetail" : 4288.88 } ], "boostValue" : 1.8 } } ] } }
Get
对文档的查询操作支持以下类型
GET<index>/_doc/<_id>HEAD<index>/_doc/<_id>GET<index>/_source/<_id>HEAD<index>/_source/<_id>
查询文档 ID 为 1 的文档信息
GET/my_goods/_doc/1
查询文档 ID 为 1 的文档是否存在,
只判断文档是否存在,head 返回的信息更少、性能更高,满足特殊业务场景使用
HEAD /my_goods/_doc/1
返回
200 - OK
只返回文档信息
查询时只返回 _source 信息
GET /my_goods/_source/1
返回
{ "goodsName" : "苹果 51英寸 4K超高清", "skuCode" : "skuCode1", "brandName" : "苹果", "closeUserCode" : [ "0" ], "channelType" : "cloudPlatform", "shopCode" : "sc00001", "publicPrice" : "8188.88", "groupPrice" : null, "boxPrice" : null, "boostValue" : 1.8}
定制化返回参数
只获取 _source 部分参数,类似数据库查询中的指定字段,而不是 select * 返回所有字段
#GET 请求模式GETmy_goods/_source/1/?_source_includes=brandName,goodsName#返回{ "brandName" : "苹果", "goodsName" : "苹果 51英寸 4K超高清"} #POST body 请求模式POSTmy_goods/_search{ "query": { "match_all": { } }, "fields": ["brandName", "goodsName"], "_source": false} #返回"hits" : [ { "_index" : "my_goods", "_type" : "_doc", "_id" : "2", "_score" : 1.0, "fields" : { "brandName" : [ "苹果" ], "goodsName" : [ "苹果 55英寸 3K超高清" ] } }, { "_index" : "my_goods", "_type" : "_doc", "_id" : "3", "_score" : 1.0, "fields" : { "brandName" : [ "美国苹果" ], "goodsName" : [ "苹果UA55RU7520JXXZ 53英寸 4K高清" ] } }, }
查询文档 ID 为 1 的文档是否存在。
只判断文档是否存在 ,Head 返回的信息更少、性能更高,满足特殊业务场景使用
HEAD /my_goods/_doc/1
返回
200 - OK
Mutil get
ES 同时支持批量查询,需要使用 _mget API,查询文档 ID 等于1和2的文档信息
GET/my_goods/_mget{ "docs": [ { "_id": "1" }, { "_id": "2" } ] }
返回
{ "docs" : [ { "_index" : "my_goods", "_type" : "_doc", "_id" : "1", "_version" : 7, "_seq_no" : 8, "_primary_term" : 1, "found" : true, "_source" : { "goodsName" : "苹果 51英寸 4K超高清", "skuCode" : "skuCode1", "brandName" : "苹果", "closeUserCode" : [ "0" ], "channelType" : "cloudPlatform", "shopCode" : "sc00001", "publicPrice" : "8188.88", "groupPrice" : null, "boxPrice" : null, "boostValue" : 1.8, "shopName" : "张三店铺" } }, { "_index" : "my_goods", "_type" : "_doc", "_id" : "2", "found" : false } ] }