分布式高级篇(四) - 商城业务 - 检索服务

# 分布式高级篇(四) - 商城业务 - 检索服务

检索服务

检索服务基础环境搭建

  • 最终效果

    image-20210115101004052

  • 效果演示

    • 1、全文检索:skuTitle -> keyword
    • 2、排序:saleCount(销量)、hotScore(热度评分)、skuPrice(价格)
    • 3、过滤:hasStock(是否有货)、skuPrice(价格区间)、brandId(品牌id 可以多选)、catalogId
    • 4、聚合:attrs(属性)
    • 5、面包屑导航
    • 6、条件删除&条件筛选联动

搭建页面环境

  • 第一步:search微服务导入依赖

     <!--模板引擎 thymeleaf-->
     <dependency>
     	<groupId>org.springframework.boot</groupId>
     	<artifactId>spring-boot-starter-thymeleaf</artifactId>
     </dependency>
     <!--dev-tools-->
     <dependency>
     	<groupId>org.springframework.boot</groupId>
     	<artifactId>spring-boot-devtools</artifactId>
     	<optional>true</optional>
     </dependency>
    

    将检索页面 index.html,拷贝进项目,放入templates目录下

    image-20210115101713282

  • 第二步:修改本地Hosts文件

    目的使 search.mall.com 生效,访问search.mall.com相当于直接访问 nginx

    C:\Windows\System32\drivers\etc
    

    image-20210115095652050

    修改成功后,保存hosts,页面访问search.mall.com查看效果(确报nginx容器启动)

    image-20210115095725521

  • 第三步:将页面所需的静态资源拷贝进nginx中的 html/static/search 目录下(利用xshell和xftp)

    image-20210115102244480

    修改nginx 转发配置 在 nginx/conf/conf.d 目录下的 mall.conf,只要是以mall.com结尾的请求地址,匹配上/static/,都会请求nginx下的静态资源。修改完成 保存退出并重启nginx容器(docker restart nginx)

    image-20210115111312980

  • 第四步:修改index.html 中的所有静态资源访问路径 href 与 src标签的 统一加上/static/search/

    image-20210115102826321

    网关服务 添加新的路由规则 Host为search.mall.com的 统一转交给search服务处理,并重启网关服务

    image-20210115102919340

测试

  • 确保search搜索服务 网关服务都成功注册进nacos服务注册中心

    image-20210115103405982

  • nginx容器配置修改并重启

  • 浏览器访问 search.mall.com,出现如下效果则搭建完成

    image-20210115104603707

检索业务分析

检索参数模型分析抽取

  • 商品检索的三个入口:

    • 1、首页--选择商品分类进入商品检索(分类catalogId)

      image-20210115132430506

    • 2、输入检索关键字展示检索页 (搜索关键字keyword)

      image-20210115132458037

    • 3、选择筛选条件进入

      image-20210115132637280

  • 检索条件分析

    • 1、全文检索:skuTitle -> keyword

    • 2、排序:saleCount(销量)、hotScore(热度评分)、skuPrice(价格)

    • 3、过滤:hasStock(是否有货)、skuPrice(价格区间)、brandId(品牌id 可以多选)、catalogId

    • 4、聚合:attrs(属性)

      完整请求参数: 
      catalog3Id=225&keyword=小米&hasStock=0/1&skuPrice=1_500&brandId=1&attrs=1_android:iOS&attrs=2_5.寸:6.5寸
      
      排序条件:sort=saleCount_asc/desc、sort=skuPrice_asc/desc、sort=hostScore_asc/desc
      hasStock(是否有货): hasStock=0/1
      skuPrice价格区间: skuPrice=1_500/_500/500_(1到500、500以内的、大于500的)
      brandId(品牌id 可以多选):brandId=1&brandId=2
      attrs(属性): attrs=1_android:iOS&attrs=2_5.寸:6.5寸
      

检索结果模型分析抽取

  • 根据页面内容,抽取返回数据

    SearchResult
    
    查询到的所有商品信息
    当前页码
    总记录数
    总页码
    当前查询到的结果,所涉及到的所有品牌
    当前查询到的结果,所涉及到的所有分类
    当前查询的结果,所涉及到的所有属性
    

检索语句构建(DSL)

  • 启动ES和kibana容器

查询部分语句

  • 在kibana中先编写DSL语句,理清思路

    GET product/_search
    {
      "query": {
        "bool": {
          "must": [
            {
              "match": {
                "skuTitle": "小米"
              }
            }
          ],
          "filter": [
            {
              "term": {
                "catalogId": "225"
              }
            },
            {
              "terms": {
                "brandId": [
                  "3",
                  "10"
                ]
              }
            },
            {
              "nested": {
                "path": "attrs",
                "query": {
                  "bool": {
                    "must": [
                      {
                        "term": {
                          "attrs.attrId": {
                            "value": "13"
                          }
                        }
                      },
                      {
                        "terms": {
                          "attrs.attrValue": [
                            "android"
                          ]
                        }
                      }
                    ]
                  }
                }
              }
            },
            {
              "term": {
                "hasStock": {
                  "value": "true"
                }
              }
            },
            {
              "range": {
                "skuPrice": {
                  "gte": 100,
                  "lte": 4000
                }
              }
            }
          ]
        }
      },
      "sort": [
        {
          "skuPrice": {
            "order": "desc"
          }
        }
      ],
      "from": 0,
      "size": 1,
      "highlight": {
        "fields": {"skuTitle": {}}, 
        "pre_tags": "<b style='color:red'>",
        "post_tags": "</b>"
      }
    }
    

    image-20210115162233410

    如果是嵌入式的属性 nested ,查询、聚合、分析都应该用嵌入式的

DSL聚合分析

ES数据迁移
  • 由于之前的ES中的 product索引 映射关系设置有些问题,我们可以新建一个新的mall_product索引,修改映射关系,并且把原有数据迁移进mall_product

    #数据迁移
    PUT mall_product
    {
      "mappings": {
        "properties": {
          "skuId": {
            "type": "long"
          },
          "spuId": {
            "type": "keyword"
          },
          "skuTitle": {
            "type": "text",
            "analyzer": "ik_smart"
          },
          "skuPrice": {
            "type": "keyword"
          },
          "skuImg": {
            "type": "keyword"
          },
          "saleCount": {
            "type": "long"
          },
          "hasStock": {
            "type": "boolean"
          },
          "hotScore": {
            "type": "long"
          },
          "brandId": {
            "type": "long"
          },
          "catalogId": {
            "type": "long"
          },
          "brandName": {
            "type": "keyword"
          },
          "brandImg": {
            "type": "keyword"
          },
          "catalogName": {
            "type": "keyword"
          },
          "attrs": {
            "type": "nested",
            "properties": {
              "attrId": {
                "type": "long"
              },
              "attrName": {
                "type": "keyword"
              },
              "attrValue": {
                "type": "keyword"
              }
            }
          }
        }
      }
    }
    
    #转移product数据到mall_product
    #固定写法
    POST _reindex
    {
      "source": {
        "index": "product"
      },
      "dest": {
        "index": "mall_product"
      }
    }
    
    #查看数据迁移情况
    GET mall_product/_search
    {
      "query": {
        "match_all": {}
      }
    }
    
聚合分析
  • 最终结果

    #检索 查询&聚合
    
    GET mall_product/_search
    {
      "query": {
        "bool": {
          "must": [
            {
              "match": {
                "skuTitle": "小米"
              }
            }
          ],
          "filter": [
            {
              "term": {
                "catalogId": "225"
              }
            },
            {
              "terms": {
                "brandId": [
                  "3",
                  "10"
                ]
              }
            },
            {
              "nested": {
                "path": "attrs",
                "query": {
                  "bool": {
                    "must": [
                      {
                        "term": {
                          "attrs.attrId": {
                            "value": "13"
                          }
                        }
                      },
                      {
                        "terms": {
                          "attrs.attrValue": [
                            "android"
                          ]
                        }
                      }
                    ]
                  }
                }
              }
            },
            {
              "term": {
                "hasStock": {
                  "value": "true"
                }
              }
            },
            {
              "range": {
                "skuPrice": {
                  "gte": 100,
                  "lte": 4000
                }
              }
            }
          ]
        }
      },
      "sort": [
        {
          "skuPrice": {
            "order": "desc"
          }
        }
      ],
      "from": 0,
      "size": 1,
      "highlight": {
        "fields": {"skuTitle": {}}, 
        "pre_tags": "<b style='color:red'>",
        "post_tags": "</b>"
      },
      "aggs": {
        "brand_agg": {
          "terms": {
            "field": "brandId",
            "size": 10
          },
          "aggs": {
            "brand_name_agg": {
              "terms": {
                "field": "brandName",
                "size": 10
              }
            },
             "brand_img_agg": {
              "terms": {
                "field": "brandImg",
                "size": 10
              }
            }
          }
        },
        "catalog_agg":{
          "terms": {
            "field": "catalogId",
            "size": 10
          },
          "aggs": {
            "catalog_name_aggs": {
              "terms": {
                "field": "catalogName",
                "size": 10
              }
            }
          }
        },
        "attr_agg":{
          "nested": {
            "path": "attrs"
          },
          "aggs": {
            "attr_id_agg": {
              "terms": {
                "field": "attrs.attrId",
                "size": 10
              },
              "aggs": {
                "attr_name_agg": {
                  "terms": {
                    "field": "attrs.attrName",
                    "size": 10
                  }
                },
                "attr_value_agg": {
                  "terms": {
                    "field": "attrs.attrValue",
                    "size": 10
                  }
                }
              }
            }
          }
        }
      }
    }
    
  • 分析过程

    当前查询到的结果 所有涉及到的所有品牌
    当前查询到的结果 所有涉及到的所有属性
    当前查询到的结果 所有涉及到的所有分类
    
    • 所有品牌(分类同理)

      GET mall_product/_search
      {
        "query": {
          "match_all": {}
        },
        "aggs": {
          "brand_agg": {
            "terms": {
              "field": "brandId",
              "size": 10
            }
          }
        }
      }
      

    image-20210116111242248

    • 想要顺便获取品牌的名称和品牌logo

      GET mall_product/_search
      {
        "query": {
          "match_all": {}
        },
        "aggs": {
          "brand_agg": {
            "terms": {
              "field": "brandId",
              "size": 10
            },
            "aggs": {
              "brand_name_agg": {
                "terms": {
                  "field": "brandName",
                  "size": 10
                }
              },
               "brand_img_agg": {
                "terms": {
                  "field": "brandImg",
                  "size": 10
                }
              }
            }
          }
        }
      }
      

      image-20210116111527354

    • 当前查询结果下的所有属性(*)

      • 属性是nested的嵌套,所以聚合分析也应该是聚合的

        GET mall_product/_search
        {
          "query": {
            "match_all": {}
          },
          "aggs": {
            "attr_agg":{
              "nested": {
                "path": "attrs"
              },
              "aggs": {
                "attr_id_agg": {
                  "terms": {
                    "field": "attrs.attrId",
                    "size": 10
                  },
                  "aggs": {
                    "attr_name_agg": {
                      "terms": {
                        "field": "attrs.attrName",
                        "size": 10
                      }
                    },
                    "attr_value_agg": {
                      "terms": {
                        "field": "attrs.attrValue",
                        "size": 10
                      }
                    }
                  }
                }
              }
            }
          }
        }
        

      image-20210116112102484

代码实现

SearchRequest构建

  • java实现动态构建出查询需要DSL语句

    • 检索

      --bool query
        --must
          --term
        --filter
        	--term
        	--terms
        	--term
        	--range
        	--nested
        	  --bool
        	  	--must
        	  	  --term
        	  	  --term
      
    • 分页、排序、高亮

      image-20210116143403016

    • 聚合

      --brand_agg
        --brand_name_agg
        --brand_img_agg
      --catalog_agg
        --catalog_name_agg
      --nestedAttr_agg
        --attr_id_agg
        	--attr_name_agg
        	--attr_value_agg
      

      image-20210116145642688

  • 测试检索语句构建是否正确

    • 第一种:

      • postman 简单请求(keyword、catalog3Id)

      image-20210116131532127

      • 打印 searchSourceBuilder,并使用在线json格式化工具 格式化

        image-20210116131431640

      • 如果语句构建正确,可以直接拷贝到kibana中查询

        image-20210116131951561

    • 第二种:

      • 复杂筛选(属性attrs、价格区间)

        image-20210116142848804

      • image-20210116143111552

  • 测试聚合语句

    • postman模拟请求

      image-20210116145757702

    • 打印出的语句,拷贝到kibana

      image-20210116150207069

SearchResponse分析&封装

  • 将ES返回结果进行封装

    1、返回的所有查询到的商品
    2、当前所有商品所涉及到的所有属性
    3、当前所有商品所涉及到的所有品牌信息
    4、当前所有商品所涉及到的所有分类信息
    5、分页信息
    

页面渲染

页面基本数据渲染

  • 检索数据展示

    image-20210117111422571

  • 刷选条件选择,请求路径拼接

    #&quot;brandId&quot; 代表"brandId" 前后双引号
    th:href="${'javascript:searchProducts(&quot;brandId&quot;,'+brand.brandId+')'}
    

    image-20210117111642760

  • 关键字检索

    image-20210117111724824

    检索条件回显

    image-20210117132928149

  • 分页数据渲染

    image-20210117133105478

  • 排序效果

    • 排序

    image-20210117142103168

    image-20210117142038846

    • 排序字段回显(页面跳转刷选之后)

      image-20210117154722635

  • 面包屑导航

    image-20210118152824857

    image-20210118152911565

  • 条件筛选联动

    image-20210118152958350

posted @ 2021-01-18 15:43  12138Ok  阅读(84)  评论(0编辑  收藏  举报