主頁 > 後端開發 > 分布式高級篇(一)ElasticSearch和商城首頁

分布式高級篇(一)ElasticSearch和商城首頁

2021-01-13 06:27:20 後端開發

分布式高級篇(一)ElasticSearch和商城首頁

ElasticSearch--全文檢索

簡介

是什么

  • ElasticSearch是一個分布式的開源搜索和分析引擎,適用于所有型別的資料,包括文本、數字、地理空間、結構化和非結構化資料
  • ElasticSearch在Apache Lucene的基礎上開發而成,由Elastic于2010年首次發布,ElasticSearch以其簡單的REST風格API、分布式特性、速度和可擴展而聞名

用途

  • ElasticSearch在速度和可擴展性方面都表現出色,而且還能夠索引多種型別的內容,這意味著其可用于多種用例:
    • 應用程式搜索
    • 網站搜索
    • 企業搜索
    • 日志處理和分析
    • 基礎設施指標和容器監測
    • 應用程式性能監測
    • 地理空間資料分析和可視化
    • 安全分析
    • 業務分析

基本概念

  • 關系圖

    image-20210102165855159

Index(索引)

  • 動詞,相當于MySQL中的insert;mysql中插入(insert)一條資料,ES中索引一條資料

  • 名詞,相當于MySQL中的DataBase

Type(型別)

  • 在index(索引)中,可以定義一個或多個型別,類似于MySQL中的Table;每一種型別的資料放在一起
ElasticSearch7-去掉type概念
  • 關系型資料庫中兩個資料表示是獨立的,即使他們里面有相同名稱的列也不影響使用但ES中不是這樣的而ES中不同type下名稱相同的filed最終在Lucene中的處理方式是一樣的

  • 兩個不同type下的兩個user_name,在ES同一個索引下其實被認為是同一個filed,你必須在兩個不同的type中定義相同的filed映射,否則,不同type中的相同欄位名稱就會在處理中出現沖突的情況,導致Lucene處理效率下降

  • 去掉type就是為了提高ES處理資料的效率

  • Elasticsearch 7.x

    URL中的type引數為可選,比如,索引一個檔案不再要求提供檔案型別

  • Elasticsearch 8.x

    不再支持URL中的type引數,解決:將索引從多型別遷移到單型別,每種型別檔案一個獨立索引

Document(檔案)

  • 保存在某個索引(index)下,某種型別(Type)的一個資料(Document),檔案是JSON格式的,Document就像是MySQL中的某個Table中的記錄

倒排索引機制

  • 舉個簡單例子

    • 在MySQL中保存一個資料:正向索引,每一條資料都有一個id對應著;這時如果想要檢索一個資料,比如電影表中檢索 紅海行動

      like 紅海行動 這時候MySQL會匹配所有記錄,看是否有紅海行動,這種檢索顯然是非常慢的操作

    • 而在ES中,在存盤資料的時候,同時會維護一張倒排索引表

      怎么維護:在存盤資料時,首先會進行分詞:將整句分拆成單詞,比如 紅海行動 拆分成 紅海、行動、紅、海...... 這時候 ES中的1號檔案記錄的是紅海行動,同時倒排索引也維護了 紅海、行動 出現在1號檔案中

    • 相關性得分:命中的分詞個數越多,分越高

    image-20210102171413524

Docker安裝

安裝ElasticSearch 7.6.1

  • 拉取鏡像

    docker pull elasticsearch:7.6.1
    
  • 運行容器并掛載

    • 啟動容器

      docker run -d --name es -p 9200:9200 -p 9300:9300 \
      -e "discovery.type=single-node" elasticsearch:7.6.1
      
    • 將組態檔、資料目錄、插件目錄拷出來做掛載

      docker cp es:/usr/share/elasticsearch/config/ /var/touchAirMallVolume/es/config/
      docker cp es:/usr/share/elasticsearch/data/  /var/touchAirMallVolume/es/data/
      docker cp es:/usr/share/elasticsearch/plugins/ /var/touchAirMallVolume/es/plugins/
      
      vim  /var/touchAirMallVolume/es/config/elasticsearch.yml
      #添加這2行
      #設定允許跨域訪問
      http.cors.enabled: true
      http.cors.allow-origin: "*"
      
    • 銷毀容器,重新以掛載方式運行

      注意:ES默認記憶體需要2g,虛擬機記憶體不足的需要設定 ES_JAVA_OPTS,否則會卡死

      #銷毀
      docker rm -f es
      
      #掛載組態檔
      docker run -d --name es  -p 9200:9200 -p 9300:9300 -v /var/touchAirMallVolume/es/config:/usr/share/elasticsearch/config \
      -v /var/touchAirMallVolume/es/data:/usr/share/elasticsearch/data  \
      -v /var/touchAirMallVolume/es/plugins:/usr/share/elasticsearch/plugins  \
      -e "discovery.type=single-node" \
      --restart=always elasticsearch:7.6.1
      
  • 訪問宿主機ip的9200埠,查看是否啟動成功

    image-20210102180053407

安裝Kibana 7.6.1

  • ES的可視化工具 版本要對應
拉取鏡像
docker pull kibana:7.6.1
運行容器
  • 先運行容器

    docker run -d --name kibana -p 5601:5601 kibana:7.6.1
    
  • 拷出組態檔,后面做掛載

    # 拷貝
    docker cp kibana:/usr/share/kibana/config/ /var/touchAirMallVolume/kibana/config/
    
    #修改配置 
    vim kibana.yml 
    
    #放開訪問地址
    0.0.0.0
    #配置es地址
    http://192.168.83.133:9200
    

    image-20210102182139475

  • 掛載運行

    # 先銷毀容器
    docker rm -f kibana
    
    # 運行容器
    docker run -d --name kibana  \
    -p 5601:5601 --restart=always \
    -v /var/touchAirMallVolume/kibana/config:/usr/share/kibana/config \
    kibana:7.6.1
    
  • 宿主機ip:5601,查看kibana圖形化界面

    image-20210102182223650

初步檢索

_cat

  • GET /_cat/nodes 查看所有節點

  • GET /_cat/health 查看es健康狀況

  • GET /_cat/master 查看主節點

  • GET /_cat/indices 查看所有索引 類似 show databases;

    image-20210102182943250

索引一個檔案(保存)

  • 保存一個資料,保存在哪個索引的哪個型別下,指定用哪個唯一標識

    PUT customer/external/1
    {
     "name":"touchair"
    }
    #發送多次是一個更新操作
    

    image-20210102183827358

    PUT和POST都可以

    POST 新增:如果不指定id,會自動生成id,指定id就回去修改這個資料,并新增版本號

    PUT 可以新增可以修改:PUT必須指定id,不指定會報錯,由于PUT需要指定id,一般用來做修改操作

查詢檔案

  • 查詢剛剛新增的資料

    GET customer/external/1
    

    image-20210102184311755

    image-20210102184449284

更新檔案

  • 更新

    POST customer/external/1/_update
    {
    	"doc":{
    		"name":"touchair2"
    	}
    }
    
    #或者
    POST customer/external/1
    {
    	"name":"touchair3"
    }
    #或者
    PUT customer/external/1
    {
    	"name":"touchair4"
    }
    
  • 區別:

    ? PUT操作總會將資料重新保存并增加version版本;

    ? POST操作 帶_update對比源資料如果一樣就不進行任何操作,檔案version不增加

    ? POST操作 不帶_update 就不會檢查源資料,始終更新

    • 看場景
      • 對于大并發更新,不帶update
      • 對于大并發查詢偶爾更新,帶update;對比更新,重新計算分配規則
  • 更新同時增加屬性

    注意 帶_update 需要帶 doc 寫法

    POST customer/external/1/_update
    {
    	"doc":{
    		"name":"post_add_condition",
    		"age":20
    	}
    }
    

    image-20210102190822427

洗掉檔案&索引

  • 洗掉檔案

    DELETE customer/external/1
    
  • 洗掉索引

    DELETE customer
    

bulk批量API

  • 批量

    POST customer/external/_bulk
    {"index":{"_id":3}}
    {"name":"奮斗逼"}
    {"index":{"_id":4}}
    {"name":"你他媽卷到我了"}
    
    #語法格式:
    #action 指定要操作的源資料
    {action:{metadata}} \n
    {request body      } \n
    
    {action:{metadata}} \n
    {request body      } \n
    

    image-20210104090609694

  • 復雜實體

    POST /_bulk
    {"delete":{"_index":"website","_type":"blog","_id":"123"}}
    {"create":{"_index":"website","_type":"blog","_id":"123"}}
    {"title":"My first blog post"}
    {"index":{"_index":"website","_type":"blog"}}
    {"title":"My second blog post"}
    {"update":{"_index":"website","_type":"blog","_id":"123","_retry_on_conflict":3}}
    {"doc":{"title":"My updated blog post"}}
    

    image-20210104091805439

  • bulk API 以此順序執行所有的action(動作),如果一個單個的動作因任何原因而失敗,它將繼續處理后面剩余的動作,當bulk API回傳時,它將提供每個動作的狀態(與發送的順序相同),所以您可以檢查是否一個指定的動作是不是失敗了

樣本測驗資料

  • es官方提供的樣本資料地址

    POST bank/accout/_bulk
    

    image-20210104093128953

    image-20210104093320586

進階檢索

  • 完全參照官方實體

Search API

  • ES支持兩種基本方式檢索
    • 一個是通過使用REST request URI 發送搜索引數(uri+檢索引數)
    • 另一個是通過使用 REST request body 來發送它們(uri+請求體)
檢索資訊
  • 請求檢索按帳號排序的銀行索引中的所有檔案

    GET /bank/_search
    {
      "query": { "match_all": {} },
      "sort": [
        { "account_number": "asc" }
      ]
    }
    

    默認情況下,回應的命中部分包含與搜索條件匹配的前10個檔案image-20210104095902588

    • took:Elasticsearch 運行查詢需要多長時間(毫秒)
    • timed_out:搜尋請求是否超時
    • _shards:搜索了多少碎片,并分別列出成功、失敗或跳過的碎片數量
    • max_score:找到的最相關檔案的分數
    • hits.total.value:找到多少相符的檔案
    • hits.sort:檔案的排序位置(當不按相關性得分排序時)
    • hits._score:檔案的相關性得分(不適用于使用match_all)
  • 每個搜索請求都是自包含的: Elasticsearch 不維護跨請求的任何狀態資訊,若要瀏覽搜索結果,請在請求中指定 from 和 size 引數

    下面的請求會得到從10到19的結果

    GET /bank/_search
    {
      "query": { "match_all": {} },
      "sort": [
        { "account_number": "asc" }
      ],
      "from": 10,
      "size": 10
    }
    

Query DSL

基本語法格式
  • ElasticSearch提供了一個可以執行查詢的json風格的DSL(domain-specific language 領域特點語言),這個被稱為Query DSL,該查詢語言非常全面,并且剛開始的時候感覺有點復雜,真正學好它的方法是從一些基礎的示例開始的
match(匹配查詢)
  • 基本型別(非字串),精確匹配

    GET /bank/_search
    {
      "query": { 
        "match": { 
          "account_number": 20
        } 
      }
    }
    
  • 字串,全文檢索

    全文檢索按照評分進行排序,會對檢索條件進行分詞匹配

    GET /bank/_search
    {
      "query": { 
        "match": { 
          "address": "Kings"
        } 
      }
    }
    
match_phrase(短語匹配)
  • 將需要匹配的值當成一個整體單詞(不分詞)進行檢索

    GET /bank/_search
    {
      "query": { 
        "match_phrase": { 
          "address": "282 Kings"
        } 
      }
    }
    
multi_match(多欄位匹配)
  • state 或者 address 包含 mill

    GET /bank/_search
    {
      "query": { 
        "multi_match": { 
          "query": "mill", 
          "fields": ["address","state"]
        } 
      }
    }
    
bool(復合查詢)
  • bool用來做復合查詢:復合陳述句可以合并任何其它查詢陳述句,包括復合陳述句,了解這一點很重要,這就意味著,復合陳述句之間可以互相嵌套,可以表達非常復雜的邏輯

    • must:必須達到must列舉的所有條件
    • must_not:必須排除must_not列舉的所有條件
    • should:應該滿足 當然也可以不滿足
    GET /_search
    {
      "query": { 
        "bool": { 
          "must": [
            { "match": { 
              "gender":   "M"        
              
            }},
            { "match": { 
              "address": "mill" 
              
            }}
          ],
          "must_not": [
            {"match": {
              "age": "28"
            }}
          ],
          "should": [
            {"match": {
              "lastname": "Wallace"
            }}
          ]
        }
      }
    }
    
filter(結果過濾)
  • 相關性得分是一個正浮點數,回傳到搜索 API 的 _ score 元欄位中,得分越高,檔案越相關,雖然每種查詢型別可以以不同的方式計算相關性分數,但分數計算還取決于查詢子句是在查詢中運行還是在過濾背景關系中運行

  • 并不是所有的查詢都需要產生分數,特別是那些僅用于filtering(過濾)的檔案,為了不計算分數ElasticSearch會自動檢查場景并且優化查詢的執行

  • must、should只有滿足條件,就會對對相關性得分提升,must_not則會被當成filter,fliter最大的一個特點就是不會對檔案的相關性得分產生影響

  • 比較,主要觀察結果中的_score

    #must 
    GET bank/_search
    {
      "query": {
        "bool": {
          "must": [
            {"range": {
              "age": {
                "gte": 18,
                "lte": 30
              }
            }}
          ]
        }
      }
    }
    
    #filter
    GET bank/_search
    {
      "query": {
        "bool": {
          "filter": [
            {"range": {
              "age": {
                "gte": 18,
                "lte": 30
              }
            }}
          ]
        }
      }
    }
    
    
term(精確查找)
  • 和match一樣,匹配某個屬性的值,全文檢索欄位用match,其他非text欄位匹配用term

    GET bank/_search
    {
      "query": {
        "term": {
          "balance": "18607"
        }
      }
    }
    
    #加上keyword 進行精確匹配(不會進行分詞)
    GET bank/_search
    {
      "query": {
        "match": {
          "address.keyword": "789 Madision"
        }
      }
    }
    GET bank/_search
    {
      "query": {
         "match": {
          "address": "789 Madision"
        }
      }
    }
    
aggregation(執行聚合)
  • 聚合提供了從資料中分組和提取資料的能力,最簡單的聚合方法大致等于SQL GROUP BY和SQL聚合函式,在ElasticSearch中,有執行搜索回傳hits(命中結果),并且同時回傳聚合結果,把一個回應中的所有hits(命中結果)分隔開的能力,這是非常強大且有效的,可以執行查詢和多個聚合,并且在一次使用中得到各自的(任何一個的)回傳結果,使用一個簡潔和簡化的API來避免網路往返

  • 搜索address中包含mill的所有人的年齡分布以及平均年齡,但不顯示這些人的詳情

    GET bank/_search
    {
      "query": {
        "match": {
          "address": "mill"
        }
      },
      "aggs": {
        "ageAgg": {
          "terms": {
            "field": "age",
            "size": 10
          }
        },
        "ageAvg":{
          "avg": {
            "field": "age"
          }
        }
      },
      "size": 0
    }
    
  • 復雜聚合

    • 按照年齡聚合,并且請求這些年齡段的這些人的平均薪資

      (子聚合)

    GET bank/_search
    {
      "query": {
        "match_all": {}
      },
      "aggs": {
        "ageAgg": {
          "terms": {
            "field": "age",
            "size": 100
          },
          "aggs": {
            "ageAvg": {
              "avg": {
                "field": "balance"
              }
            }
          }
        }
      },
      "size": 0
    }
    
    • 查出所有年齡分布,并且這些年齡段中M的平均薪資和F的平均薪資以及這個年齡段的總體平均薪資

      GET bank/_search
      {
        "query": {
          "match_all": {}
        },
        "aggs": {
          "ageAgg": {
            "terms": {
              "field": "age",
              "size": 100
            },
            "aggs": {
              "fAvg": {
                "avg": {
                  "field": "balance"
                  }
                },
              "genderAgg": {
                "terms": {
                  "field": "gender.keyword",
                  "size": 10
                },
                "aggs": {
                  "balAvg": {
                    "avg": {
                      "field": "balance"
                    }
                  }
                }
              }
            }
          }
        },
        "size": 0
      }
      

      image-20210104145004155

Mapping

  • Mapping是用來定義一個檔案(document),以及它所包含的屬性(field)是如何存盤索引的,比如,使用mapping來定義:
    • 哪些字串屬性應該被看做全文本屬性(full text fields)
    • 哪些屬性包含數字,日期或者地理位置
    • 檔案中的所有屬性是否都能被索引(_all配置)
    • 日期的格式
    • 自定義映射規則來執行動態添加屬性

6.0版本之后,移除了type

  • 查看映射

    GET /bank/_mapping
    

分詞

  • 一個tokenizer(分詞器)接受一個字符流,將之分割為獨立的tokens(詞元,通常是獨立的單詞),然后輸出tokens流,

    例如,whitespace tokenizer 遇到空白字符時分割文本,它會將文本“Quick brown fox!” 分割為[Quick,brown,fox!]

    tokenizer(分詞器)還負責記錄各個term(詞條)的順序或position位置(用于phrase短語和 word proximity詞近鄰查詢),以及term(詞條)所代表的的原始word(單詞)的開始和結束的字符偏移量(character offsets)用于高亮顯示搜索的內容

  • ElasticSearch 提供了很多內置的分詞器,可以用來構建 custom analyzers(自定義分詞器)

安裝ik分詞器
  • 下載地址 7.6.1

  • 進入容器內部 plugins目錄 或者宿主機的掛載目錄

    • 解壓下載的檔案
    • 洗掉壓縮包
    • 修改目錄名字為 ik
  • 重啟es,并驗證是否安裝成功

    • 進入容器 /bin 目錄下執行

      elasticsearch-plugin list
      

      image-20210104160937257

  • 測驗分詞

    • ik_smart 最少切分

      image-20210104162121041

    • ik_max_word 最細力度劃分

      image-20210104162057598

安裝Nginx
  • 拉取鏡像

    docker pull nginx
    
  • 先隨便啟動一個nginx實體,只是為了復制配置,方便掛載

    #啟動
    docker run -p 80:80 --name nginx -d nginx
    
    #將容器內的組態檔拷貝到當前目錄 我這里是在 /var/touchAirMallVolume 目錄下執行的
    docker container cp nginx:/etc/nginx .
    

    image-20210104165805743

  • 修改目錄

    mv nginx conf
    mkdir nginx
    mv conf nginx/
    

    image-20210104170035704

  • 洗掉舊的容器,重新掛載啟動

    #洗掉舊容器
    docker rm -f nginx
    
    #掛載啟動
    docker run -d --name nginx  \
    -p 80:80 --restart=always \
    -v /var/touchAirMallVolume/nginx/html:/usr/share/nginx/html \
    -v /var/touchAirMallVolume/nginx/logs:/var/log/nginx \
    -v /var/touchAirMallVolume/nginx/conf:/etc/nginx \
    nginx
    
  • 驗證nginx

    • 進入宿主機nginx下的html目錄,創建一個簡單的html

      image-20210104170904943

      image-20210104170917816

    • 在 nginx/html/ 新增es目錄,創建遠程詞庫

      image-20210104171809641

      image-20210104171826888

自定義擴展詞庫
  • 前提:安裝好nginx

  • 修改ik分詞器的 IKAnalyzer.cfg.xml

    cd  /var/touchAirMallVolume/es/plugins/ik/config
    
    vim IKAnalyzer.cfg.xml 
    

image-20210104171856792

  • 重啟es容器,并測驗自定義分詞效果

    image-20210104172154180

Elasticsearch-Rest_Client

  • 官方RestClient,封裝了ES操作,API層次分明,上手簡單

    最終選擇Elasticsearch-Rest_Client(elasticsearch-rest-high-level-client)

    官方地址

  • 如果你使用的es版本有對應的spring-data-elasticsearch,建議參照官網使用,封裝了更簡易的API

    spring-data

springboot整合

  • 導包(對應版本)

    <dependency>
    	<groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-high-level-client</artifactId>
        <version>7.6.2</version>
    </dependency>
    

配置

  • 配置類 (全部參照官方檔案)

    elasticsearch-rest-high-level-client配置類

  • MallElasticSearchConfig

    @Configuration
    public class MallElasticSearchConfig {
    
        public static final RequestOptions COMMON_OPTIONS;
        static {
            RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
    //        builder.addHeader("Authorization", "Bearer " + TOKEN);
    //        builder.setHttpAsyncResponseConsumerFactory(
    //                new HttpAsyncResponseConsumerFactory
    //                        .HeapBufferedResponseConsumerFactory(30 * 1024 * 1024 * 1024));
            COMMON_OPTIONS = builder.build();
        }
    
        @Bean
        public RestHighLevelClient esRestClient() {
            RestHighLevelClient client = new RestHighLevelClient(
                    RestClient.builder(
                            new HttpHost("192.168.83.133", 9200, "http")));
            return client;
        }
    }
    

使用

  • mall-search單元測驗

    • 測驗是否注入成功

       	@Resource
          private RestHighLevelClient restHighLevelClient;
      
          @Test
          public void test() {
              System.out.println(restHighLevelClient);
          }
      
    • 測驗存盤(更新)資料到es

       	/**
           * 測驗存盤資料到es
           * 更新也可以
           */
          @Test
          public void testSave() throws IOException {
              IndexRequest indexRequest = new IndexRequest("users");
              indexRequest.id("1");
      //        indexRequest.source("username", "ZhSan", "age", 18, "gender","男");
              User user = new User();
              user.setUserName("ZhSan");
              user.setGender("男");
              user.setAge(18);
              String jsonStr = JSONUtil.toJsonStr(user);
              indexRequest.source(jsonStr, XContentType.JSON);//要保存的內容
              //執行操作
              IndexResponse index = restHighLevelClient.index(indexRequest, MallElasticSearchConfig.COMMON_OPTIONS);
              System.out.println(index);
          }
      
      	@Data
          class User{
              private String userName;
              private Integer age;
              private String gender;
          }
      
    • 測驗復雜檢索

          /**
           * 復雜檢索
           */
          @Test
          public void searchData() throws IOException {
              //1、創建檢索請求
              SearchRequest searchRequest = new SearchRequest();
              //2、指定索引
              searchRequest.indices("bank");
              //3、指定DSL,檢索條件
              SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
              //3.1、構造檢索條件
              //searchSourceBuilder.query();
              //searchSourceBuilder.from();
              //searchSourceBuilder.size();
              //searchSourceBuilder.aggregation();
              searchSourceBuilder.query(QueryBuilders.matchQuery("address", "mill"));
              //聚合操作
              //按照年齡的值分布進行聚合
              TermsAggregationBuilder ageAgg = AggregationBuilders.terms("ageAgg").field("age").size(10);
              searchSourceBuilder.aggregation(ageAgg);
              //計算平均薪資
              AvgAggregationBuilder balanceAvgAgg = AggregationBuilders.avg("balanceAvgAgg").field("balance");
              searchSourceBuilder.aggregation(balanceAvgAgg);
      
              System.out.println("檢索條件:"+searchSourceBuilder.toString());
              searchRequest.source(searchSourceBuilder);
      
              //4、執行檢索
              SearchResponse searchResponse = restHighLevelClient.search(searchRequest, MallElasticSearchConfig.COMMON_OPTIONS);
              //5、分析結果
              System.out.println(searchResponse.toString());
              //5.1 獲取所有查到的資料
              SearchHits hits = searchResponse.getHits();
              SearchHit[] hitsHits = hits.getHits();
              for (SearchHit searchHit : hitsHits) {
                  /**
                   * "_index" : "bank",
                   * "_type" : "accout",
                   * "_id" : "1",
                   * "_score" : 1.0,
                   * "_source" : {}
                   */
                  String sourceAsString = searchHit.getSourceAsString();
                  Account account = JSON.parseObject(sourceAsString, Account.class);
                  System.out.println(account);
              }
              //5.2 獲取這次檢索到的分析資訊
              Aggregations aggregations = searchResponse.getAggregations();
      //        for (Aggregation aggregation : aggregations.asList()) {
      //            System.out.println("當前聚合:"+aggregation.getName());
      //        }
              Terms ageAggRes = aggregations.get("ageAgg");
              for (Terms.Bucket bucket : ageAggRes.getBuckets()) {
                  String keyAsString = bucket.getKeyAsString();
                  System.out.println("年齡:" + keyAsString+"===>"+bucket.getDocCount());
              }
      
              Avg balanceAvgAggRes = aggregations.get("balanceAvgAgg");
              System.out.println("平均薪資:" + balanceAvgAggRes.getValue());
      
          }
      
          /**
           * bank 賬戶資訊
           */
          @Data
          @ToString
          static class Account {
              private int account_number;
              private int balance;
              private String firstname;
              private String lastname;
              private int age;
              private String gender;
              private String address;
              private String employer;
              private String email;
              private String city;
              private String state;
          }
      

商品上架

spu在es中的存盤模型分析

  • 如果每個sku都存盤規格引數,會有冗余存盤,因為每個spu對應的sku的規格引數都一樣,但是如果將規格引數單獨建立索引會出現檢索時出現大量資料傳輸的問題,會阻塞網路

    因此我們選用第一種存盤模型,以空間換時間

    image-20210107085213232

向ES添加商品屬性映射

  • es-product 屬性映射

    PUT product
    {
      "mappings": {
        "properties": {
          "skuId":{
            "type":"long"
          },
          "spuId":{
            "type":"keyword"
          },
          "skuTitle":{
            "type":"text",
            "analyzer": "ik_smart"
          },
          "skuPrice":{
            "type":"keyword"
          },
          "skuImg":{
            "type":"keyword",
            "index": false,
            "doc_values": false
          },
          "saleCount":{
            "type":"long"
          },
          "hasStock":{
            "type":"boolean"
          },
          "hotScore":{
            "type":"long"
          },
          "brandId":{
            "type":"long"
          },
          "catalogId":{
            "type":"long"
          },
          "brandName":{
            "type":"keyword",
            "index": false,
            "doc_values": false
          },
           "brandImg":{
            "type":"keyword",
            "index": false,
            "doc_values": false
          },
           "catalogName":{
            "type":"keyword",
            "index": false,
            "doc_values": false
          },
          "attrs":{
            "type": "nested",
            "properties": {
              "attrId":{
                "type":"long"
              },
              "attrName":{
                "type":"keyword",
                "index": false,
                "doc_values": false
              },
              "attrValue":{
                "type":"keyword"
              }
            }
          }
        }
      }
    }
    

商品上架功能實作

  • 實作方法

    com.touch.air.mall.product.service.impl.SpuInfoServiceImpl.up()
    

Feign呼叫流程

  • 問題思考:遠程呼叫失敗 是否會重復呼叫?介面冪等性;重試機制?
  1. 構造請求資料,將物件轉為json

    #原始碼
    RequestTemplate template=buildTemplateFromArgs.create(argv)
    
  2. 發送請求進行執行(執行成功會解碼回應資料)

    executeAndDecode(template)
    
  3. 執行請求會有重試機制

    while(true)
    {
        try{
          executeAndDecode(template);  
        }catch(){
            try{retryer.continueOrPropagate(e);}catch(){throw ex;}
            continue;
        }
    }
    

商城首頁

動靜分離

  • 整體架構

    image-20210107143720825

整合thymeleaf渲染首頁

  • 添加依賴

    <!--模板引擎 thymeleaf-->
     <dependency>
     	<groupId>org.springframework.boot</groupId>
     	<artifactId>spring-boot-starter-thymeleaf</artifactId>
     </dependency>
    
  • 匯入靜態資源 --首頁資源

    • index檔案夾 添加到商品微服務的resources/static

    • index.html 檔案添加到商品微服務的 resources/templates

      image-20210107145550826

  • application.yml 添加配置

    • 靜態資源都放在static檔案夾下就可以按照路徑直接訪問

    • 頁面放在templates下,直接訪問 SpringBoot,訪問專案的時候,默認會找index.html

      #頁面測驗
      #訪問靜態資源
      http://localhost:12000/index/css/GL.css
      
      #訪問html頁面
      http://localhost:12000
      
    • 查看 WebMvcAutoConfiguration原始碼

      • OrderedHiddenHttpMethodFilter 處理頁面發送的rest請求

      • InternalResourceViewResolver 視圖決議器進行拼串(前綴、后綴)

        image-20210107163208997

        image-20210107165405016

      • addResourceHandlers 資源處理器

      • WelcomePageHandlerMapping 歡迎頁 默認靜態資源路徑、默認加載index.html

        image-20210107163803367

        image-20210107164014998

  • 檔案

    thymeleaf官方檔案

頁面修改不重啟服務實時更新

  • 引入 dev-tools

     <dependency>
     	<groupId>org.springframework.boot</groupId>
     	<artifactId>spring-boot-devtools</artifactId>
     	<optional>true</optional>
     </dependency>
    
  • 修改完頁面 直接ctrl+shift+F9 重新自動編譯,如果修改了代碼配置,推薦重啟 避免bug

渲染一級分類資料

  • 介面

    com.touch.air.mall.product.web.IndexController.indexPage
    #請求url
    http://localhost:12000/
    http://localhost:12000/index.html
    
  • 頁面

    templates/index.html
    

渲染二級&三級分類資料

  • 介面

    com.touch.air.mall.product.web.IndexController.getCatalogJson
    #請求url
    http://localhost:12000/index/catalog.json
    
  • ajax請求

    catalogLoader.js
    
    index/catalog.json
    

    image-20210108104305308

nginx搭建域名訪問環境

正向代理與反向代理

  • 正向代理:如上網,隱藏客戶端資訊(常見VPN)

    image-20210108105238229

  • 反向代理:屏蔽內網服務器資訊,負載均衡訪問

    image-20210108105257281

nginx+Windows搭建域名訪問環境

windows
  • windows hosts檔案

    C:\Windows\System32\drivers\etc
    

    image-20210108110952430

  • 修改完成后,使用域名訪問ES測驗

    image-20210108111644705

nginx進行反向代理
  • nginx組態檔

    conf/nginx.conf

    image-20210108112644058

    • nginx.conf 表面所有的server塊所在的位置

      nginx/conf.d 目錄下的 default.conf
      

      image-20210108113346717

  • 將所有來自mall.com的請求,都轉到商品服務

    cp nginx/conf.d 目錄下的default.conf  mall.conf
    vim mall.conf
    
    指定server_name 為 mall.com   (與頁面請求的Host對應)
    配置轉發的地址 本地商品服務
    

    image-20210108133908497

    image-20210108133654289

    • 重啟nginx容器
    • 此時頁面訪問 mall.com ,會展示商城首頁
域名訪問,負載均衡到網關
  • nginx官網

    使用nginx 在http協議中負載均衡

    image-20210108134913460

  • 修改 nginx.conf

    #添加上游服務器的服務地址
    #轉交給本地網關
    upstream mall {
            server 192.168.0.105:9527;
        }
    
  • 修改 nginx/conf.d 目錄下的mall.conf

    #對應上游服務器的名字
    location / {
            proxy_pass http://mall;
        }
    

注意:nginx代理到網關的時候,會默認丟掉很多資訊,包括host資訊等,在這里如果沒有host資訊,網關路由將匹配不到,也就無法轉發到指定的服務

  • 修改配置,讓nginx保存host

    vim mall.conf
    #添加以下配置
    proxy_set_header Host $host
    

    重啟nginx容器

  • 添加網關路由處理規則

    #配置在vue路由的最下面
    - id: mall_host
      uri: lb://touch-air-mall-product
      predicates:
        - Host=**.mall.com
    

    重啟網關服務

  • 瀏覽器輸入 mall.com 訪問成功

    image-20210108141652149

最終域名映射效果

  • 請求介面 mall.com
  • 請求頁面 mall.com
  • nginx 直接代理給網關,網關進行判斷
    • 如果/api/**,轉交給對應的服務器
    • 如果是滿足域名,轉交給對應的服務

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/247925.html

標籤:Java

上一篇:[labuladong演算法小抄]如何k個一組反轉鏈表

下一篇:萬萬沒想到,面試中,連 ClassLoader類加載器 也能問出這么多問題…..

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more