05-ElasticSearch高級搜索

来源:https://www.cnblogs.com/OnlyOnYourself-lzw/archive/2022/08/10/16570714.html
-Advertisement-
Play Games

2、ElasticSearch高級搜索 Elasticsearch提供了基於JSON的DSL(Domain Specific Language)來定義查詢。常見的查詢類型如下所示 ①、查詢所有 查詢出所有數據,一般測試用;例如 match_all 如下圖所示 ②、全文檢索(full text)查詢 ...


2、ElasticSearch高級搜索

  • Elasticsearch提供了基於JSON的DSL(Domain Specific Language)來定義查詢。常見的查詢類型如下所示
    • ①、查詢所有
      • 查詢出所有數據,一般測試用;例如
        • match_all
        • 如下圖所示
    • ②、全文檢索(full text)查詢
      • 利用分詞器對用戶輸入內容分詞,然後去倒排索引庫中匹配,例如
        • match_query
        • multi_match_query
    • ③、精確查詢
      • 根據精確詞條值查找數據,一般是查找keyword、數值、日期、boolean等類型的欄位,例如
        • ids
        • range
        • term
    • ④、地理(geo)查詢
      • 根據經緯度查詢,例如
        • geo_distance
        • geo_bounding_box
    • ⑤、複合(compound)查詢
      • 複合查詢可以將上述各種查詢條件組合起來,合併查詢條件,例如
      • bool
      • function_score

2.1、全文檢索查詢

2.1.1、使用場景

  • 全文檢索查詢的基本流程如下所示
    • ①、對用戶搜索的內容做分詞,得到詞條
    • ②、根據詞條去倒排索引庫中匹配,得到文檔id
    • ③、根據文檔id找到文檔,把所有匹配結果以並集或交集返回給用戶
  • 比較常用的場景包括
    • 商城的輸入框搜索
    • 百度搜索框搜索
  • 因為是拿著詞條去匹配,因此參與搜索的欄位也必須是可分詞的text類型的欄位

2.1.2、DSL語句格式

  • 常見的全文檢索查詢包括

    • match查詢:單欄位查詢
    • multi_match查詢:多欄位查詢,任意一個欄位符合條件就算符合查詢條件
  • match查詢語法如下所示

    • GET /indexName/_search
      {
        "query": {
          "match":{
            "FIELD": "TEXT"
          }
        }
      }
      
  • match_all查詢語法如下

    • GET /indexName/_search
      {
        "query": {
          "multi_match": {
            "query": "TEXT",
            "fileds": ["FILED1", "FILED2"]
          }
        }
      }
      

2.1.3、match查詢DSL語句示例&&RestAPI示例

①、DSL語句

  • 比如要搜索name欄位中存在 如家酒店,DSL語句如下所示

    • GET hotel/_search
      {
        "query": {
          "match": {
            "name": "如家酒店"
          }
        },
        "size": 2		# size的意思是只顯示n條數據
      }
      
  • 搜索結果如下所示

  • 結果分析

    • 因為name欄位是類型是text,搜索的時候會對這個欄位進行分詞

    • 如搜索如家酒店,那麼就會分詞稱為如家酒店相當於會搜索三次,並取這三次搜索的並集(ES預設的是並集),所以搜索的命中率才會如此之高

      • 通俗的來說
        • 並集就相當於搜索到name like %如家%算一條數據,搜索到酒店也算一條數據
        • 那麼交集就跟它相反,必須是name like %如家酒店%才能算是一條數據
    • 那麼如何取交集呢?,如下所示

      • DSL

        • # 取交集,並集是or
          GET hotel/_search
          {
            "query": {
              "match": {
                "name": {
                  "query": "如家酒店",
                  "operator": "and"
                }
              }
            }
          }
          
      • 運行結果

②、RestAPI

math_all
  • 代碼如下所示

    • package com.coolman.hotel.test;
      
      import com.coolman.hotel.pojo.HotelDoc;
      import com.fasterxml.jackson.core.JsonProcessingException;
      import com.fasterxml.jackson.databind.ObjectMapper;
      import org.apache.lucene.search.TotalHits;
      import org.elasticsearch.action.search.SearchRequest;
      import org.elasticsearch.action.search.SearchResponse;
      import org.elasticsearch.client.RequestOptions;
      import org.elasticsearch.client.RestHighLevelClient;
      import org.elasticsearch.index.query.MatchAllQueryBuilder;
      import org.elasticsearch.index.query.QueryBuilder;
      import org.elasticsearch.index.query.QueryBuilders;
      import org.elasticsearch.search.SearchHit;
      import org.elasticsearch.search.SearchHits;
      import org.junit.jupiter.api.Test;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.boot.test.context.SpringBootTest;
      
      import java.io.IOException;
      
      @SpringBootTest
      public class FullTextSearchDemo {
          // 註入 RestHighLevelClient對象
          @Autowired
          private RestHighLevelClient restHighLevelClient;
      
      // jackson
      private final ObjectMapper objectMapper = new ObjectMapper();
      
      /**
       * 查詢所有測試
       */
      @Test
      public void testMatchAll() throws IOException {
          // 1. 創建一個查詢請求對象
          SearchRequest searchRequest = new SearchRequest("hotel");   // 指定索引
      
          // 2. 添加查詢的類型
          MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
          searchRequest.source().query(matchAllQueryBuilder);     // source就相當於{}
          searchRequest.source().size(100);     // RestAPI預設返回的是10條數據,可以更改size的屬性,即可自定義返回的數據量
      
          // 3. 發出查詢的請求,得到響應結果
          SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
      
          // 4. 處理響應的結果
          handlerResponse(response);
      
      }
      
      /**
       * 用來處理響應數據(相當於解析返回的JSON數據)
       * @param response
       */
      private void handlerResponse(SearchResponse response) throws JsonProcessingException {
          // 1. 得到命中的數量(即總記錄數量)
          SearchHits hits = response.getHits();
          long totalCount = hits.getTotalHits().value;// 總記錄數
          System.out.println("總記錄數量為:" + totalCount);
      
          // 2. 獲取本次查詢出來的列表數據
          SearchHit[] hitsArray = hits.getHits();
          for (SearchHit hit : hitsArray) {
              // 得到json字元串
              String json = hit.getSourceAsString();
              // 將json字元串轉換為實體類對象
              HotelDoc hotelDoc = objectMapper.readValue(json, HotelDoc.class);
              System.out.println(hotelDoc);
          }
      }
      

      }

      ​~~~

match
  • 代碼如下所示

    •     /**
           * 單欄位查詢
           */
          @Test
          public void testMatch() throws IOException {
              // 1. 創建查詢請求對象
              SearchRequest searchRequest = new SearchRequest("hotel");
      
              // 2. 添加查詢的類型
              MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("name", "如家酒店");
              searchRequest.source().query(matchQueryBuilder);
      
              // 3. 發出查詢請求,得到響應數據
              SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
      
              // 4. 處理響應的結果
              handlerResponse(response);
          }
      

自行運行查看結果即可

2.1.4、multi_match查詢DSL語句示例&&RestAPI示例

DSL語句

  • 比如搜索namebrand欄位中出現如家酒店的數據

    • DSL語句如下所示

      • GET hotel/_search
        {
          "query": {
            "multi_match": {
              "query": "如家酒店",
              "fields": ["name", "brand"]
            }
          }
        }
        
    • 運行結果如下所示

    • 不過多欄位查詢的使用很少,因為多欄位查詢會使得查詢效率變慢

    • 一般都會在創建映射的時候,使用copy_to將指定欄位的值拷貝到另一個欄位,如自定義的all欄位

    • 這樣子就可以使用單欄位查詢,提高查詢效率

RestAPI

跟單欄位查詢差不多,只不過使用QueryBuilders創建的對象略有不同罷了

  • 代碼如下所示

    •     /**
           * 多欄位查詢
           */
          @Test
          public void testMultiMatch() throws IOException {
              // 1. 創建查詢請求球體對象
              SearchRequest searchRequest = new SearchRequest("hotel");
      
              // 2. 添加要查詢的欄位
      //        MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("如家酒店", "name", "brand", "bussiness");
      //        searchRequest.source().query(multiMatchQueryBuilder);
      
              // 因為在創建映射的時候使用了copy_to,索引上面的多欄位查詢等價於下麵的單欄位查詢
              MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("all", "如家酒店");
              searchRequest.source().query(matchQueryBuilder);
      
              // 3. 執行查詢操作,得到響應對象
              SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
      
              // 4. 處理響應對象
              handlerResponse(response);
      
          }
      

2.2、精準查詢

2.2.1、使用場景

  • 精確查詢一般是查找keyword、數值、日期、boolean等類型的欄位,所以不會對搜索條件分詞,常見的有如下
    • term
      • 根據詞條精確值查詢,相當於equals=
    • range
      • 根據值的範圍查詢,相當於>=<=betweenand

2.2.2、DSL語句格式

①、term查詢

  • 因為精確查詢的欄位搜索的是不分詞的欄位,因此查詢的條件也必須是不分詞的詞條

  • 查詢的時候,用戶輸入的內容跟自動值完全匹配的時候才認為符合條件

  • 如果用戶輸入的內容過多,反而搜索不到數據

  • 語法說明

    • # term 精確查詢
      GET /indexName/_search
      {
        "query": {
          "term": {
            "FILED": {
              "value": "VALUE"
            }
          }
        }
      }
      
  • 示例

    • 輸入精確詞條
    • 輸入精確詞條

②、range查詢

  • 範圍查詢,一般應用在對數值類型做範圍過濾的時候。比如做價格範圍過濾

  • 基本語法

    • # range 精確查詢
      # gte表示大於等於;gt表示大於
      # lte表示小於等於;lt表示小於
      GET /indexName/_search
      {
        "query": {
          "range": {
            "FIELD": {
              "gte": 10,
              "lte": 20
            }
          }
        }
      }
      
  • 示例

    • 查詢price大於等於200,小於等於500的酒店

2.2.3、RestAPI

  • term查詢

    • 代碼如下所示

    •     /**
           * term 精確查詢
           */
          @Test
          public void testTermQuery() throws IOException {
              // 1. 創建查詢請求對象
              SearchRequest searchRequest = new SearchRequest("hotel");
      
              // 2. 添加要查詢的欄位
              TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("brand", "如家");
              searchRequest.source().query(termQueryBuilder);
      
              // 3. 發出查詢的請求,獲取響應結果
              SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
      
              // 4. 處理響應的結果
              handlerResponse(response);
      
          }
      
  • range查詢

    • 代碼如下所示

    •     /**
           * range 精確查詢
           */
          @Test
          public void testRangeQuery() throws IOException {
              // 1. 創建查詢請求對象
              SearchRequest searchRequest = new SearchRequest("hotel");
      
              // 2. 添加查詢的欄位
              RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("price");
              rangeQuery.gte(300);    // 大於等於300
              rangeQuery.lte(500);    // 小於等於500
              searchRequest.source().query(rangeQuery);
      
              // 3. 執行查詢操作,獲取響應結果
              SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
      
              // 4. 處理響應結果
              handlerResponse(response);
          }
      

2.3、地理坐標查詢

2.3.1、使用場景

2.3.2、DSL語句格式

①、矩形範圍查詢

  • 矩形範圍查詢,也就是geo_bounding_box查詢,查詢坐標落在某個矩形範圍的所有文檔

  • 查詢的時候,需要指定矩形的左上、右下兩個點的坐標,然後畫出一個矩形,落在該矩形內的都是符合條件的點,如下所示

  • 語法如下所示

    • # 地理位置查詢(矩形查詢)
      GET hotel/_search
      {
        "query": {
          "geo_bounding_box": {
            "location": {
              "top_left": {
                "lat": 31.1,
                "lon": 121.5
              },
              "bottom_right": {
                "lat": 30.9,
                "lon": 121.7
              }
            }
          }
        }
      }
      
  • 示例

②、附近查詢

  • 附近查詢,也叫做距離查詢(geo_distance)

    • 查詢到指定中心小於某個距離值的所有文檔
  • 換句話來說,在地圖上找一個點作為圓心,以指定距離為半徑,畫一個圓,落在圓內的坐標都算符合條件,如下所示

  • 語法如下所示

    • GET hotel/_search
      {
        "query": {
          "geo_distance": {
            "distance": "15km",
            "location": "31.21,121.5"
          }
        }
      }
      
  • 示例

2.3.3、RestAPI

①、矩形範圍查詢

  • 代碼如下所示

    •     /**
           * 地理坐標矩形查詢
           */
          @Test
          public void testGeoBoundingBoxSearch() throws IOException {
              // 1. 創建查詢請求對象
              SearchRequest searchRequest = new SearchRequest("hotel");
      
              // 2. 添加要查詢的欄位
              // 指定要查詢的欄位為 location
              GeoBoundingBoxQueryBuilder geoBoundingBoxQueryBuilder = QueryBuilders.geoBoundingBoxQuery("location");
              
              // 指定 topLeft的坐標
              geoBoundingBoxQueryBuilder.topLeft().resetLat(31.1);
              geoBoundingBoxQueryBuilder.topLeft().resetLon(121.5);
      
              // 指定 bottom_right的坐標
              geoBoundingBoxQueryBuilder.bottomRight().resetLat(30.9);
              geoBoundingBoxQueryBuilder.bottomRight().resetLon(121.7);
              
              searchRequest.source().query(geoBoundingBoxQueryBuilder);
      
              // 3. 發起請求
              SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
      
              // 4. 處理返回的數據
              handlerResponse(response);
          }
      

②、附近查詢

  • 代碼如下所示

    •     /**
           * 地理坐標附近查詢(圓形)
           */
          @Test
          public void testGeoDistanceSearch() throws IOException {
              // 1. 創建查詢請求對象
              SearchRequest searchRequest = new SearchRequest("hotel");
      
              // 2. 添加要查詢的欄位
              // 指定要查詢的欄位是 location
              GeoDistanceQueryBuilder geoDistanceQueryBuilder = QueryBuilders.geoDistanceQuery("location");
      
              // 指定中心點坐標
              geoDistanceQueryBuilder.point(new GeoPoint(31.21, 121.5));
              // 指定要查詢的範圍距離
              geoDistanceQueryBuilder.distance("15km");
      
              searchRequest.source().query(geoDistanceQueryBuilder);
      
              // 3. 發起查詢請求
              SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
      
              // 4. 處理返回的數據
              handlerResponse(response);
          }
      

2.4、複合查詢之布爾查詢

2.4.1、使用場景

  • 布爾查詢是一個或多個查詢子句的組合,每一個子句就是一個子查詢,子查詢的組合方式有如下幾種
    • ①、must必須匹配每個子查詢,類似"與"(and),must的條件參與算分
    • ②、should選擇性匹配子查詢,類似"或"(or)
    • ③、must_not:必須匹配,不參與算分,類似"非"(not)
    • ④、filter:效果和must一樣,都是and。必須匹配,filter的條件不參與算分
  • 常見的應用場景
    • 比如在搜索酒店的時候,除了關鍵字搜索以外,我們還可能根據品牌、價格、城市等欄位過濾
    • 每一個不同的欄位,其查詢的條件、方式都不一樣,必須是多個不同的查詢,而要組合這些查詢,就必須使用bool查詢
  • 註意事項
    • 不過需要註意的是,搜索的時候,參與算分的欄位越多,查詢的性能也越差;因此這種多條件查詢的時候,可以按照如下類似方法解決
      • 搜索框的關鍵字搜索,是全文檢索查詢,使用must查詢,參與算分
      • 其他過濾條件,採用filter查詢,不參與算分

2.4.2、DSL語句格式

  • DSL語句如下所示

    • GET hotel/_search
      {
        "query": {
          "bool": {
            "must": [
              {
                "term": {
                  "city": {
                    "value": "上海"
                  }
                }
              }
            ],
            "should": [
              {
                "term": {
                  "brand": {
                    "value": "皇冠假日"
                  }
                }
              },
              {
                "term": {
                  "brand": {
                    "value": "華美達"
                  }
                }
              }
            ],
            "must_not": [
              {
                "range": {
                  "price": {
                    "lte": 500
                  }
                }
              }
            ],
            "filter": {
              "range": {
                "score": {
                  "gte": 45
                }
              }
            }
          }
        }
      }
      
    • 這個DSL語句的意思通俗來說就是

      • ①、城市必須是上海
      • ②、品牌可以是皇冠假日或者華美達
      • ③、價格必須小於等於500
      • ④、得分必須大於等於45
  • 示例

    • 需求如下所示

      • 搜索名字包含"如家酒店",價格不高於400,在坐標31.21,121.5,周圍10km範圍的酒店
    • 分析

      • ①、名稱搜索,屬於全文檢索查詢,應該參與算分
      • ②、價格不高於400,用range過濾查詢,不參與算分(可以放到must_not中,當然也可以放到filter中,使用lte表示小於等於400)
      • ③、周圍10km範圍內,用geo_distance查詢,屬於過濾條件,不參與算分,放到filter
    • DSL語句如下所示

      • GET hotel/_search
        {
          "query": {
            "bool": {
              "must": [
                {
                  "match": {
                    "name": "如家酒店"
                  }
                }
              ], 
              "must_not": [
                {
                  "range": {
                    "price": {
                      "gt": 400
                    }
                  }
                }
              ],
              "filter": {
                "geo_distance": {
                  "distance": "10km",
                  "location": {
                    "lat": 31.21,
                    "lon": 121.5
                  }
                }
              }
            }
          }
        }
        
      • PS:在kibana中編寫filter中的坐標信息的時候自動補全有些bug,kibana會報錯distacne_unitlocation不能共存,所以應該把這個單位刪除,然後在distance欄位上添加雙引號的同時帶上單位

2.4.3、RestAPI

  • 代碼如下所示

    • /**
           * 複合查詢之布爾查詢
           */
          @Test
          public void testBooleanQuery() throws IOException {
              // 1. 創建查詢請求對象
              SearchRequest searchRequest = new SearchRequest("hotel");
      
              // 2. 添加要查詢的欄位
              BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
              // must
              MatchQueryBuilder brand = QueryBuilders.matchQuery("name", "如家酒店");
              boolQueryBuilder.must(brand);
              // must_not
              RangeQueryBuilder price = QueryBuilders.rangeQuery("price").gt(400);
              boolQueryBuilder.mustNot(price);
              // filter
              GeoDistanceQueryBuilder location = QueryBuilders.geoDistanceQuery("location").point(new GeoPoint(31.21, 121.5)).distance("10km");
              boolQueryBuilder.filter(location);
      
              searchRequest.source().query(boolQueryBuilder);
      
              // 3. 執行查詢,得到響應數據
              SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
      
              // 4. 處理響應數據
              handlerResponse(response);
      
          }
      

2.5、複合查詢之算分函數查詢

2.5.1、使用場景

  • 當我們使用match查詢的時候,文檔結果會根據搜索詞條的關聯度打分(_score),返回結果時按照分值降序排序
    • 可以自行查詢查看驗證
  • 在Elasticsearch中,早期使用的打分演算法是TF-IDF演算法,公式如下
    • TF(詞條頻率):描述某一詞在一篇文檔中出現的頻繁程度。出現越多,分值越高,反之,分值月底
    • IDF(逆文檔頻率):通過公式可以看到,詞條出現的文檔數量越多,分值越低,反之越高
  • 在後來的5.1版本升級後,Elasticsearch將演算法改進為BM25演算法,公式如下
  • TF-IDF演算法有一個缺陷,就是詞條頻率越高,文檔得分也會越高,單個詞條對文檔影響較大。而BM25則會讓單個詞條的演算法有一個上限,曲線更加平滑
  • 根據相關度打分是比較合理的需求,但合理的不一定是產品經理需要的
  • 以某度為例,在搜索的結果中,並不是相關度越高,排名越靠前;而是誰掏的錢多,排名就越靠前
  • 要想人為控制相關性算分,就需要利用Elasticsearch中的function score查詢

2.5.2、DSL語句格式

  • 可以通過下圖來理解算分函數查詢的DSL語句基本格式
  • function score 查詢中包含四部分內容
    • ①、原始查詢條件
      • query部分,基於這個條件搜索文檔,並且基於BM25演算法給文檔打分,原始算分(query score)
    • ②、過濾條件
      • filter部分,符合該條件的文檔才會重新算分
    • ③、算分函數
      • 符合filter條件的文檔要根據這個函數做運算,得到的函數算分(function score),有四種函數
        • weight:函數結果是常量
        • field_value_factor:以文檔中的某個欄位值作為函數結果
        • random_score:以隨機數作為函數結果
        • script_score:自定義算分函數演算法
    • ④、運算模式
      • 算分函數的結果、原始查詢的相關性算分,兩者之間的運算方式,包括
        • multiply:相乘
        • replace:用function score替換query score
        • 其它,例如:sumavgmaxmin
  • function score 的運行流程如下所示
    • a. 根據原始條件查詢搜索文檔,並且計算相關性算分,稱為原始算分(query score)
    • b. 根據過濾條件,過濾文檔
    • c. 符合過濾條件的文檔,基於算分函數的運算,得到函數算分(function score)
    • d. 將原始算分(query score)和函數算分(function score)基於運算模式做運算,得到最終結果,作為相關性算分
  • 因此,其中的關鍵點是
    • 過濾條件:決定哪些文檔的算分被修改
    • 算分函數:決定函數算分的演算法
    • 運算模式:決定最終算分結果

需求

  • 讓"如家"這個品牌的酒店排名靠前一點

  • 這個需求很簡單,可以理解為如下幾部分

    • ①、原始條件:不確定,可以任意變化
    • ②、過濾條件:brand = "如家"
    • ③、算分函數:可以簡單粗暴,直接使用weight給固定的算分結果
    • ④、運算模式:比如求和
  • 因此DSL語句如下所示

    • GET hotel/_search
      {
        "query": {
          "function_score": {
            "query": {
              "match": {
                "name": "酒店"
              }
            },
            "functions": [
              {
                "filter": {
                  "term": {
                    "brand": "如家"
                  }
                },
                "weight": 10
              }
            ],
            "boost_mode": "sum"
          }
        }
      }
      
  • 結果如下所示

  • 原始搜索結果如下所示

2.5.3、RestAPI

  • 代碼如下所示,可以對照著DSL語句進行編寫

    •     /**
           * 複合查詢之算分函數查詢
           */
          @Test
          public void testFunctionScoreQuery() throws IOException {
              // 1. 創建查詢請求對象
              SearchRequest searchRequest = new SearchRequest("hotel");
      
              // 2. 添加查詢的請求體
              searchRequest.source().query(   // query
                      QueryBuilders.functionScoreQuery(   // function_score
                              QueryBuilders.matchQuery("name", "酒店"), // match
                              new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{  // functions
                                      new FunctionScoreQueryBuilder.FilterFunctionBuilder(    // filter
                                              QueryBuilders.termQuery("brand", "如家"), // term
                                              ScoreFunctionBuilders.weightFactorFunction(10)  // weight
                                      )
                              }
                      ).boostMode(CombineFunction.SUM)    // boost_mode
              );
      
      
              // 3. 執行查詢,獲取響應數據
              SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
      
              // 4. 處理響應數據
              handlerResponse(response);
      
          }
      

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • margin:auto為什麼不垂直居中 margin:auto是具有強烈計算意味的關鍵字,用來計算元素對應方向上應該獲得的剩餘空間大小。 行內元素margin:auto; 不能水平居中在一行的中央位置(行內元素不獨占一行)。 position定位屬性大家都不會陌生,添加position屬性的元素可以 ...
  • vivo 互聯網前端團隊-Yang Kun 一、背景 在團隊中,我們因業務發展,需要用到桌面端技術,如離線可用、調用桌面系統能力。什麼是桌面端開發?一句話概括就是:以 Windows 、macOS 和 Linux 為操作系統的軟體開發。對此我們做了詳細的技術調研,桌面端的開發方式主要有 Native ...
  • 蒼穹之邊,浩瀚之摯,眰恦之美; 悟心悟性,善始善終,惟善惟道! —— 朝槿《朝槿兮年說》 寫在開頭 作為一名Java Developer,我們都清楚地知道,主要從搭載Linux系統上的伺服器程式來說,使用Java編寫的是”單進程-多線程"程式,而用C++語言編寫的,可能是“單進程-多線程”程式,“多 ...
  • 技術 Leader 是一個對綜合素質要求非常高的崗位,不僅要有解具體技術問題的架構能力,還要具備團隊管理的能力,更需要引領方向帶領團隊/平臺穿越迷茫進階到下一個境界的能力。所以通常來說技術 Leader 的技能是虛實結合的居多,繁雜的工作偏多。為此我把自己在工作中經常用到的思考技巧也做了一個整理。 ...
  • 社交是一種永恆的需求,既有生存層面的必要,也有情感上的渴求。而隨著互聯網開始統治這個時代,社交被搬到了網上,並且越來越成為主流,社交也在發展成互聯網產品的一個重要賽道。本文將介紹Soul是如何破解Z世代社交密碼的。 文章目錄 01 年輕人的社交密碼 02 為什麼對年輕人來說,Soul是那個對的產品? ...
  • 統一術語(戰略設計) 我們將通過DDD完成業務與技術的完整落地 統一 領域模型術語 DDD模式名稱 技術 技術設計術語 技術術語 技術設計模式 業務 領域模型術語 DDD模式名稱 業務術語 設計無關的業務術語 清晰的事件流 DDD 領域驅動設計是一個有關軟體開發的方法論,它提出基於領域開發的開發模式 ...
  • 3、ElasticSearch搜索結果處理 3.1、排序 Elasticsearch預設是根據相關度算分(_score)來排序,但是也支持自定義方式對搜索結果排序,可以排序的欄位類型有如下幾種 keyword類型 數值類型 地理坐標類型 日期類型 ... 3.1.1、普通欄位排序 keyword、數 ...
  • @Autowired註解是spring用來支持依賴註入的核心利器之一,但是我們或多或少都會遇到required a single bean, but 2 were found(2可能是其他數字)的問題,接下來我們從源碼的角度去看為什麼會出現這個問題,以及這個問題的解法是什麼? 首先我們寫一個demo ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...