• 分布式高级篇(四)


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

    检索服务

    检索服务基础环境搭建

    • 最终效果

      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:WindowsSystem32driversetc
      

      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

  • 相关阅读:
    【转】Javascript面向对象编程(二):构造函数的继承
    【转】Javascript 面向对象编程(一):封装
    js 碎片整理(变量声明,函数作用域)
    js函数表达式和函数声明的区别
    jquery实现input输入框实时输入触发事件代码(点击历史记录也会触发)
    JS控制,返回上一页之后强行刷新一次
    疯狂JAVA16课之对象与内存控制
    [转] C++的引用传递、指针传递参数在java中的相应处理方法
    Markdown编辑器测试
    15-01-07 C# 面向过程 08
  • 原文地址:https://www.cnblogs.com/w3angb/p/14293034.html
Copyright © 2020-2023  润新知