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
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...