主頁 >  其他 > ElasticSearch在分布式專案中的使用

ElasticSearch在分布式專案中的使用

2021-10-16 08:27:18 其他

ElasticSearch的使用

概念

ElasticSearch是一個基于Lucene的搜索搜索引擎,它提供了一個分布式多用戶能力的全文搜索引擎,基于RESTful web介面,Elasticsearch是用Java開發的,并作為Apache許可條款下的開放原始碼發布,是當前流行的企業級搜索引擎,設計用于云計算中,能夠達到實時搜索,穩定,可靠,快速,安裝使用方便,

同類產品 solr

直奔主題,整體思路

使用目的: 作為門戶網站的分布式專案,其中的搜索欄,如果使用模糊搜索,不僅效率低,且對資料庫造成較大的壓力,千萬級的資料無法在短時間內搜索,用戶體驗不好,所以必須使用ElasticSearch來幫助我們開發搜索模塊

思路如下 圖所示:

在這里插入圖片描述

開發商品模塊介面,目的: 通過資料庫查詢,獲取商品資訊,屆時通過OpenFeign宣告介面,給search模塊微服務呼叫,用來初始化ES中的index索引

1. 商品微服務的介面開發

a. 正常介面開發: 使用的是MybatisPlus去連接Mysql的資料庫,在對應的表,mall_goods , mall_goods_brand , mall_goods_cat 通過三表的連查去查找所有審核通過的商品資訊

b. 使用OpenFeign的介面宣告,去宣告介面,給其他需要的微服務呼叫

goods微服務中的依賴

<!-- mvc 起步依賴 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</depedency>
<!-- nacos的注冊與發現 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</depedency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</depedency>
<!-- 端點監控 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</depedency>
<!-- druid起步依賴 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.10</version>
</depedency>
<!-- mysql驅動 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</depedency>
<!-- mybatisplus 起步依賴 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.0</version>
</depedency>
<!-- entity依賴 -->
<dependency>
    <groupId>com.fengmi</groupId>
    <artifactId>fengmi-entity</artifactId>
    <version>1.0-SNAPSHOT</version>
</depedency>

goods微服務中的mapper層

public interface MallGoodsMapper extends BaseMapper<MallGoods> {

    // 查詢所有審核通過的商品
    public List<MallGoods> findAllGoodsAudited();
}

goods微服務中的mapper層映射檔案

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.fengmi.mapper.MallGoodsMapper">
    <!-- public List<MallGoods> findAllGoodsAudited(); -->
    <resultMap id="findAllGoodsAuditedMap" type="mallgoods">
        <id column="spu_id" property="spuId"/>
        <result column="goods_name" property="goodsName"/>
        <result column="price" property="price"/>
        <result column="album_pics" property="albumPics"/>
        <association property="mallGoodsBrand" javaType="mallGoodsBrand">
            <id column="brandId" property="id"/>
            <result column="brandName" property="name"/>
        </association>
        <association property="cat1" javaType="MallGoodsCat">
            <id column="cat1Id" property="id"/>
            <result column="cat1Name" property="name"/>
        </association>
        <association property="cat2" javaType="MallGoodsCat">
            <id column="cat2Id" property="id"/>
            <result column="cat2Name" property="name"/>
        </association>
        <association property="cat3" javaType="MallGoodsCat">
            <id column="cat3Id" property="id"/>
            <result column="cat3Name" property="name"/>
        </association>
    </resultMap>

    <select id="findAllGoodsAudited" resultMap="findAllGoodsAuditedMap">
        SELECT
        goods.spu_id,
        goods.goods_name,
        goods.price,
        goods.album_pics,
        goods.brand_id AS brandId,
        brand.name AS brandName,
        goods.category1_id AS cat1Id,
        cat1.name AS cat1Name,
        goods.category2_id AS cat2Id,
        cat2.name AS cat2Name,
        goods.category3_id AS cat3Id,
        cat3.name AS cat3Name
        FROM mall_goods goods
        LEFT JOIN mall_goods_brand brand ON goods.brand_id = brand.id
        LEFT JOIN mall_goods_cat cat1 ON goods.category1_id = cat1.id
        LEFT JOIN mall_goods_cat cat2 ON goods.category2_id = cat2.id
        LEFT JOIN mall_goods_cat cat3 ON goods.category3_id = cat3.id
        WHERE goods.audit_status = 1;
    </select>
</mapper>

goods微服務中的service層

public interface IMallGoodsService extends IService<MallGoods> {

    // 查詢所有審核通過上線的商品資訊
    public List<MallGoods> findAllGoodsInfo();
}
@Service
public class MallGoodsServiceImpl extends ServiceImpl<MallGoodsMapper, MallGoods> implements IMallGoodsService {

    @Override
    public List<MallGoods> findAllGoodsInfo() {
        return this.baseMapper.findAllGoodsAudited();
    }
}

goods微服務中的controller層

@RestController
@RequestMapping("/goods")
public class MallGoodsController {

    @Autowired
    private IMallGoodsService goodsService;

    @GetMapping("findAllGoodsInfo")
    public List<MallGoods> findAllGoodsInfo() {
        return goodsService.findAllGoodsInfo();
    }
}

goods微服務進行OpenFeign的介面宣告

這里需要創建一個模塊,專門用于OpenFeign的介面宣告,注意分包!!!

import com.fengmi.goods.MallGoods;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

@FeignClient("fengmi-goods")
@RequestMapping("goods")
public interface GoodsApi {

    @GetMapping("findAllGoodsInfo")
    public List<MallGoods> findAllGoodsInfo();

}

2. search模塊微服務的介面開發

這一塊微服務主要分兩個步驟:

a. 初始化elasticsearch的索引和域 => 這需要查詢到資料庫中的資料(呼叫以上介面即可),通過ElasticsearchRestTemplate中的 save()方法去初始化

b. 查詢操作 => 需要系結查詢的條件,如bool復合查詢,highlight高亮顯示,aggs分組,filters過濾等,這需要熟練使用ElasticSearchRestTemplate的Api

2.1 開發所需依賴

<!-- es的起步依賴 -->
<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
 </dependency>

<!-- nacos的注冊與發現 -->
 <dependency>
     <groupId>com.alibaba.cloud</groupId>
     <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
 </dependency>

 <dependency>
     <groupId>com.alibaba.cloud</groupId>
     <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
 </dependency>

<!-- springMVC 起步依賴 -->
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-web</artifactId>
 </dependency>

<!-- 端點監控 -->
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-actuator</artifactId>
 </dependency>

<!-- entity依賴 -->
 <dependency>
     <groupId>com.fengmi</groupId>
     <artifactId>fengmi-entity</artifactId>
     <version>1.0-SNAPSHOT</version>
 </dependency>

<!-- OpenFeign 的宣告模塊的依賴 -->
 <dependency>
     <groupId>com.fengmi</groupId>
     <artifactId>fengmi-api</artifactId>
     <version>1.0-SNAPSHOT</version>
 </dependency>

2.2 引導類中需要掃描

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableDiscoveryClient
@EnableFeignClients(basePackages = {"com.fengmi.api.goods"}) // 掃描才能呼叫openfeign的介面哦
public class SearchApp {
    public static void main(String[] args) {
        SpringApplication.run(SearchApp.class,args);
    }
}

2.3 初始化ElasticSearch的介面

service 的介面
public interface ISearchService {
    // 初始化elasticsearch  看這里!!!!
    public ResultVO initEs();

    // 使用es查詢并分頁
    public PageResultVO<ESGoods> searchAndPageByES(SearchDTO searchDTO);
}
service的實作

明確

所謂的elasticsearch初始化主要分兩個步驟:

  1. 洗掉之前可能存在的索引,對應Api => ElasticSearchRestTemplate.deleteIndex(對應的物體Class),之后再通過設計的物體去創建索引
  2. 查詢資料庫中的資料,然后遍歷轉換為設定的索引物體類,之后使用save()方法匯入資料

至此,索引,域創建完畢,資料匯入完畢

  • 索引物體類

物體類的設計對于其中欄位要明確三個維度:

  1. 要不要分詞,通過 type 去確認欄位的型別,如果type確認欄位是 TEXT 那么就可以通過 analyzer去確定分詞的型別是 ik_max_word 或者 ik_smart ;如果欄位的型別設定為了Keyword,表示這個欄位是不使用分詞的,就是其本身
  2. 要不要建立索引,通過 index 屬性來設定,一般的欄位都是需要建立索引的,但如圖片地址等一些 不會用到的搜索條件,我們可以不建立索引
  3. 要不要儲存,通過 store 屬性來設定,一般來說我們設計的欄位都是需要儲存的
package com.fengmi.entity;

import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

import java.util.Date;
@Data
@Document(indexName = "es-goods",  shards = 1, replicas = 0)
public class ESGoods {

    @Id
    private Long spuId;                        // spuId

    @Field(type = FieldType.Text, analyzer = "ik_max_word",store=true)
    private String goodsName;

    @Field(type=FieldType.Long,index=true,store=true)
    private Long brandId;                       // 品牌id
    
    @Field(type = FieldType.Keyword,index=true,store=true)
    private String brandName;                   //品牌名稱

     @Field(type=FieldType.Long,index=true,store=true)
    private Long cid1id;                        // 1級分類id
    @Field(type = FieldType.Keyword,index=true,store=true)
    private String cat1name;                    // 1級分類名稱
   
     @Field(type=FieldType.Long,index=true,store=true)
    private Long cid2id;                        // 2級分類id
     @Field(type = FieldType.Keyword,index=true,store=true)
    private String cat2name;                    // 2級分類名稱

    @Field(type=FieldType.Long,index=true,store=true)
    private Long cid3id;                        // 3級分類id
     @Field(type = FieldType.Keyword,index=true,store=true)
    private String cat3name;                    // 3級分類名稱

	 @Field(type=FieldType.Date,index=true,store=true,format = DateFormat.date_time)
    private Date createTime;                    // 創建時間
    @Field(type=FieldType.Double,index=true,store=true)
    private Double price;                       // 價格,spu默認的sku的price
    @Field(type = FieldType.Keyword,index = false,store=true)
    private String smallPic;                    // 圖片地址
}
  • 物體類設計完畢,下面開始做es初始化的作業,代碼如下:
@Service
public class SearchService implements ISearchService {

    @Autowired
    private GoodsApi goodsApi;

    @Autowired
    private ElasticsearchRestTemplate restTemplate;

    @Override
    public ResultVO initEs() {
        // 洗掉原有索引
        restTemplate.deleteIndex(ESGoods.class);
        // 初始化索引
        restTemplate.createIndex(ESGoods.class);
        // 初始化分詞器
        restTemplate.putMapping(ESGoods.class);

        // 遠程呼叫goodsApi 查詢商品資訊
        List<MallGoods> allGoodsInfo = goodsApi.findAllGoodsInfo();

        if (allGoodsInfo == null || allGoodsInfo.size() < 0) {
            return new ResultVO(false, "初始化失敗");
        }

        // 遍歷 將物體類的映射設定到索引庫
        List<ESGoods> goodsList = allGoodsInfo.stream().map(spu -> {
            ESGoods esGoods = new ESGoods();
            // id
            esGoods.setSpuId(spu.getSpuId());
            // brand 品牌資訊
            esGoods.setBrandId(spu.getMallGoodsBrand().getId());
            esGoods.setBrandName(spu.getMallGoodsBrand().getName());
            // 分類資訊
            esGoods.setCid1id(spu.getCat1().getId());
            esGoods.setCat1name(spu.getCat1().getName());
            esGoods.setCid2id(spu.getCat2().getId());
            esGoods.setCat2name(spu.getCat2().getName());
            esGoods.setCid3id(spu.getCat3().getId());
            esGoods.setCat3name(spu.getCat3().getName());
            // 維護創建時間,后面可以做排序處理
            esGoods.setCreateTime(new Date());
            // 商品名稱
            esGoods.setGoodsName(spu.getGoodsName());
            esGoods.setPrice(spu.getPrice().doubleValue());
            // 圖片是字串形式,需要做處理
            String albumPics = spu.getAlbumPics();
            // 對字串做處理要先進行非空判斷
            if (!StringUtils.isEmpty(albumPics)) {
                String[] split = albumPics.split(",");
                // 非空判斷
                if (split != null && split.length > 0) {
                    esGoods.setSmallPic(spu.getAlbumPics());
                }
            }
            return esGoods;
        }).collect(Collectors.toList());

        // 保存到es中
        restTemplate.save(goodsList);

        return new ResultVO(true, "elasticsearch初始化成功");
    }
}       
提供初始化的controller介面
@RestController
@RequestMapping("search")
public class SearchController {

    @Autowired
    private ISearchService searchService;
	
    // 初始化介面方法
    @RequestMapping("initES")
    public ResultVO initES() {
        return searchService.initEs();
    }
}    

至此,初始化的作業進行完畢

2.4 使用ElasticSearch查詢介面開發

接下來就是重頭戲了,使用elasticsearch來作為查詢的作業

2.4.1 思路
  1. 先做基本查詢的功能,需要多個域匹配,所以我們采用復合查詢bool中的should來操作
  2. 基本查詢完成之后進行分頁的操作,可以通過設定分頁來完成
  3. 對輸入的關鍵字進行設定,采用高亮設定,以實作查詢
  4. 分組,聚合查詢,完成品牌和種類串列的實作
  5. 過濾,這里必須使用過濾,對上述查詢的結果進行過濾的操作不會影響分數!
  6. 排序,對結果集添加排序的操作,這里實作價格的排序,其他方法是一致的
  • 先看看原型界面

在這里插入圖片描述

明確要求

  1. 查詢時,首先是要匹配幾個域的,分別是: 商品的名稱goodsName,商品的品牌brandName,商品三級分類的名稱cat3name,而這幾個域只要有一個匹配上就展示,這樣能搜索到的商品就更多
  2. 域的分詞,goodsName采用 ik_max_word分詞,這樣也能搜索到更多的產品,以提升用戶的購買率,品牌和商品三級分類則可以不需要分詞
  3. 以上要求組合起來可以得到:需要使用復合查詢,should條件拼接
  4. 順帶可以將分頁也處理了,只需添加分頁設定即可
2.4.2 基本分頁查詢
public PageResultVO<ESGoods> searchAndPageByES(SearchDTO searchDTO) {
        // 非空判斷
        if (searchDTO == null) {
            return new PageResultVO<>(false, "引數不合法");
        }
        // 從es中查詢
        // 1. 多重匹配查詢
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // 2. 條件匹配,需要分詞,匹配商品名稱,從條件dto中獲取,先做非空判斷,keyword為空是查所有
        if (!StringUtils.isEmpty(searchDTO.getKeyword())) {
            MatchQueryBuilder goodsName = QueryBuilders.matchQuery("goodsName", searchDTO.getKeyword());
            // 3. 條件匹配,不分詞,匹配品牌名稱
            TermQueryBuilder brandName = QueryBuilders.termQuery("brandName", searchDTO.getKeyword());
            // 4. 條件匹配 , 不分詞, 匹配3級分類名稱
            TermQueryBuilder cat3name = QueryBuilders.termQuery("cat3name", searchDTO.getKeyword());
            // 5. 使用should匹配,只要有一個符合就可以,這樣符合電商的性質
            boolQueryBuilder.should(goodsName).should(brandName).should(cat3name);
        }
        // 6. 設定分頁資訊,防止惡意攻擊
        if (searchDTO.getPage() <= 0 || searchDTO.getSize() <= 0) {
            searchDTO.setPage(1);
            searchDTO.setSize(5);
        }
        PageRequest pageRequest = PageRequest.of(searchDTO.getPage() - 1, searchDTO.getSize());
    
    	// 7. 創建并設定查詢物件
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder()
                // 設定查詢條件
                .withQuery(boolQueryBuilder)
}
    
  • searchDTO類
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SearchDTO {
    // 搜索的關鍵字
    private String keyword;

    // 當前頁
    private Integer page = 1;

    // 每頁條數
    private Integer size = 5;

    // 過濾所需欄位
    private String brandNameFilter;

    private String cat3NameFilter;

    // 排序所需欄位
    private String sortField;

}
  • 回應類:ResultVO 和PageResultVO
@Data
@AllArgsConstructor
@NoArgsConstructor
@RequiredArgsConstructor
public class ResultVO {

    @NonNull
    private boolean success;  //標記操作的狀態

    @NonNull
    private String msg;    //錯誤資訊


    private Object data ;   //資料

}
@Data
@AllArgsConstructor
@NoArgsConstructor
@RequiredArgsConstructor
public class PageResultVO<T> {
    private Long total; // 總記錄數

    private Integer pages; // 總頁數

    private List<T> data;  // 每頁資料

    @NonNull
    private boolean success; // 回應標志位
    @NonNull
    private String msg;  // 回應資訊
}
2.4.3 高亮設定

對于查詢的關鍵字keyword可以設定高亮顯示,這樣的用戶體驗會更好

    @Override
    public PageResultVO<ESGoods> searchAndPageByES(SearchDTO searchDTO) {
        // 非空判斷
        if (searchDTO == null) {
            return new PageResultVO<>(false, "引數不合法");
        }
        // 從es中查詢
        // 1. 多重匹配查詢
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // 2. 條件匹配,需要分詞,匹配商品名稱,從條件dto中獲取,先做非空判斷
        if (!StringUtils.isEmpty(searchDTO.getKeyword())) {
            MatchQueryBuilder goodsName = QueryBuilders.matchQuery("goodsName", searchDTO.getKeyword());
            // 3. 條件匹配,不分詞,匹配品牌名稱
            TermQueryBuilder brandName = QueryBuilders.termQuery("brandName", searchDTO.getKeyword());
            // 4. 條件匹配 , 不分詞, 匹配3級分類名稱
            TermQueryBuilder cat3name = QueryBuilders.termQuery("cat3name", searchDTO.getKeyword());
            // 5. 使用should匹配,只要有一個符合就可以,這樣符合電商的性質
            boolQueryBuilder.should(goodsName).should(brandName).should(cat3name);
        }
        // 6. 設定分頁資訊,防止惡意攻擊
        if (searchDTO.getPage() <= 0 || searchDTO.getSize() <= 0) {
            searchDTO.setPage(1);
            searchDTO.setSize(5);
        }
        PageRequest pageRequest = PageRequest.of(searchDTO.getPage() - 1, searchDTO.getSize());

        // 7. 創建并設定查詢物件
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder()
                // 設定查詢條件
                .withQuery(boolQueryBuilder)
                // 設定分頁條件
                .withPageable(pageRequest)
                // 設定高亮
                .withHighlightBuilder(getHighlightBuilder("goodsName"))
            
        // 8. 查詢
        SearchHits<ESGoods> search = restTemplate.search(nativeSearchQueryBuilder.build(), ESGoods.class);
        // 9. 設定總條數
        PageResult pageResultVO = new PageResult();
        pageResultVO.setTotal(search.getTotalHits());

        // 10. 獲取命中物件
        List<SearchHit<ESGoods>> searchHits = search.getSearchHits();
        // 11. 遍歷,處理每頁資料,和高亮
        List<ESGoods> esGoodsList = searchHits.stream().map(hit -> {
            // 獲取內容
            ESGoods esGoods = hit.getContent();
            // 設定高亮資訊
            Map<String, List<String>> highlightFields = hit.getHighlightFields();
            highlightFields.forEach((k, v) -> {
                // v 即是每個資訊中高亮的陣列屬性,做非空判斷
                if (v != null && v.size() > 0) {
                    // 如果k與域名相同,那么才設定高亮
                    if ("goodsName".equals(k)) {
                        esGoods.setGoodsName(v.get(0));
                    }
                }
            });
            return esGoods;
        }).collect(Collectors.toList());
        
        // 設定每頁資訊
        pageResultVO.setData(esGoodsList);
        return pageResultVO;
    }
	// 設定高亮欄位 自定義方法
    private HighlightBuilder getHighlightBuilder(String... fields) {
        // 高亮條件
        HighlightBuilder highlightBuilder = new HighlightBuilder(); //生成高亮查詢器
        for (String field : fields) {
            highlightBuilder.field(field);//高亮查詢欄位
        }
        highlightBuilder.requireFieldMatch(false);     //如果要多個欄位高亮,這項要為false
        highlightBuilder.preTags("<span style=\"color:red\">");   //高亮設定
        highlightBuilder.postTags("</span>");
        //下面這兩項,如果你要高亮如文字內容等有很多字的欄位,必須配置,不然會導致高亮不全,文章內容缺失等
        highlightBuilder.fragmentSize(800000); //最大高亮分片數
        highlightBuilder.numOfFragments(0); //從第一個分片獲取高亮片段

        return highlightBuilder;
    }
}
2.4.4 聚合統計品牌和分類資訊

回憶一下在kibana中我們是怎么做聚合的,是與query同級,使用aggs來聚合,設定聚合組名,聚合桶只能使用term不分詞,設定field欄位對應的域

那么在代碼中使用聚合也是在與查詢同級

public PageResultVO<ESGoods> searchAndPageByES(SearchDTO searchDTO) {
        // 非空判斷
        if (searchDTO == null) {
            return new PageResultVO<>(false, "引數不合法");
        }
        // 從es中查詢
        // 1. 多重匹配查詢
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // 2. 條件匹配,需要分詞,匹配商品名稱,從條件dto中獲取,先做非空判斷
        if (!StringUtils.isEmpty(searchDTO.getKeyword())) {
            MatchQueryBuilder goodsName = QueryBuilders.matchQuery("goodsName", searchDTO.getKeyword());
            // 3. 條件匹配,不分詞,匹配品牌名稱
            TermQueryBuilder brandName = QueryBuilders.termQuery("brandName", searchDTO.getKeyword());
            // 4. 條件匹配 , 不分詞, 匹配3級分類名稱
            TermQueryBuilder cat3name = QueryBuilders.termQuery("cat3name", searchDTO.getKeyword());
            // 5. 使用should匹配,只要有一個符合就可以,這樣符合電商的性質
            boolQueryBuilder.should(goodsName).should(brandName).should(cat3name);
        }
        // 6. 設定分頁資訊,防止惡意攻擊
        if (searchDTO.getPage() <= 0 || searchDTO.getSize() <= 0) {
            searchDTO.setPage(1);
            searchDTO.setSize(5);
        }
        PageRequest pageRequest = PageRequest.of(searchDTO.getPage() - 1, searchDTO.getSize());

        // 6.1設定聚合
    	// terms設定組名,field設定對應域,size設定桶的個數
        TermsAggregationBuilder brandNameTermsAggregationBuilder = AggregationBuilders.terms("brandAgg").field("brandName").size(30);
        TermsAggregationBuilder cat3nameTermsAggregationBuilder = AggregationBuilders.terms("cat3Agg").field("cat3name").size(30);

        // 7. 創建并設定查詢物件
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder()
                // 設定查詢條件
                .withQuery(boolQueryBuilder)
                // 設定分頁條件
                .withPageable(pageRequest)
                // 設定高亮
                .withHighlightBuilder(getHighlightBuilder("goodsName"))
                // 設定聚合
                .addAggregation(brandNameTermsAggregationBuilder)
                .addAggregation(cat3nameTermsAggregationBuilder);
        // 8. 查詢
        SearchHits<ESGoods> search = restTemplate.search(nativeSearchQueryBuilder.build(), ESGoods.class);
        // 9. 設定總條數
        PageResult pageResultVO = new PageResult();
        pageResultVO.setTotal(search.getTotalHits());
        // 10. 獲取命中物件
        List<SearchHit<ESGoods>> searchHits = search.getSearchHits();
        // 11. 遍歷,處理每頁資料,和高亮
        List<ESGoods> esGoodsList = searchHits.stream().map(hit -> {
            // 獲取內容
            ESGoods esGoods = hit.getContent();
            // 設定高亮資訊
            Map<String, List<String>> highlightFields = hit.getHighlightFields();
            highlightFields.forEach((k, v) -> {
                // v 即是每個資訊中高亮的陣列屬性,做非空判斷
                if (v != null && v.size() > 0) {
                    // 如果k與域名相同,那么才設定高亮
                    if ("goodsName".equals(k)) {
                        esGoods.setGoodsName(v.get(0));
                    }
                }
            });
            return esGoods;
        }).collect(Collectors.toList());
        // 12. 獲取聚合資訊
        Aggregations aggregations = search.getAggregations();
        // 從指定的域中獲取聚合的資訊
        Terms brandName = aggregations.get("brandAgg");
        Terms cat3name = aggregations.get("cat3Agg");
        // 獲取桶
        List<? extends Terms.Bucket> brandNameBuckets = brandName.getBuckets();
        List<? extends Terms.Bucket> cat3nameBuckets = cat3name.getBuckets();
        // 遍歷獲取
        List<String> brandNameList = brandNameBuckets.stream().map(item -> (String) item.getKey()).collect(Collectors.toList());
        pageResultVO.setBrandNameList(brandNameList);
        List<String> cat3NameList = cat3nameBuckets.stream().map(item -> (String) item.getKey()).collect(Collectors.toList());
        pageResultVO.setCat3NameList(cat3NameList);
        // 設定每頁資訊
        pageResultVO.setData(esGoodsList);
        return pageResultVO;
    }


    // 設定高亮欄位
    private HighlightBuilder getHighlightBuilder(String... fields) {
        // 高亮條件
        HighlightBuilder highlightBuilder = new HighlightBuilder(); //生成高亮查詢器
        for (String field : fields) {
            highlightBuilder.field(field);//高亮查詢欄位
        }
        highlightBuilder.requireFieldMatch(false);     //如果要多個欄位高亮,這項要為false
        highlightBuilder.preTags("<span style=\"color:red\">");   //高亮設定
        highlightBuilder.postTags("</span>");
        //下面這兩項,如果你要高亮如文字內容等有很多字的欄位,必須配置,不然會導致高亮不全,文章內容缺失等
        highlightBuilder.fragmentSize(800000); //最大高亮分片數
        highlightBuilder.numOfFragments(0); //從第一個分片獲取高亮片段

        return highlightBuilder;
    }
2.4.5 過濾查詢,通過聚合出的品牌名稱和分類名稱過濾

為什么要使用過濾而非在復合條件中添加?

關鍵字: 分數

使用復合條件查詢對結果的分數會有影響,就會影響到排序,頁面圖片的改變就會變大,這里我們希望是不影響結果的分數,那么只能使用過濾的方式來實作

回憶一下在kibana中怎么使用過濾的:
過濾在bool復合查詢中,使用filters與bool同級,使用term或者terms來設定過濾的欄位,該欄位是不分詞的
所以在代碼中使用過濾也是在bool中組合,而非與查詢同級
public PageResultVO<ESGoods> searchAndPageByES(SearchDTO searchDTO) {
        // 非空判斷
        if (searchDTO == null) {
            return new PageResultVO<>(false, "引數不合法");
        }
        // 從es中查詢
        // 1. 多重匹配查詢
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // 2. 條件匹配,需要分詞,匹配商品名稱,從條件dto中獲取,先做非空判斷
        if (!StringUtils.isEmpty(searchDTO.getKeyword())) {
            MatchQueryBuilder goodsName = QueryBuilders.matchQuery("goodsName", searchDTO.getKeyword());
            // 3. 條件匹配,不分詞,匹配品牌名稱
            TermQueryBuilder brandName = QueryBuilders.termQuery("brandName", searchDTO.getKeyword());
            // 4. 條件匹配 , 不分詞, 匹配3級分類名稱
            TermQueryBuilder cat3name = QueryBuilders.termQuery("cat3name", searchDTO.getKeyword());
            // 5. 使用should匹配,只要有一個符合就可以,這樣符合電商的性質
            boolQueryBuilder.should(goodsName).should(brandName).should(cat3name);
        }
        // 6. 設定分頁資訊,防止惡意攻擊
        if (searchDTO.getPage() <= 0 || searchDTO.getSize() <= 0) {
            searchDTO.setPage(1);
            searchDTO.setSize(5);
        }
        PageRequest pageRequest = PageRequest.of(searchDTO.getPage() - 1, searchDTO.getSize());

        // 6.1設定聚合
        TermsAggregationBuilder brandNameTermsAggregationBuilder = AggregationBuilders.terms("brandAgg").field("brandName").size(30);
        TermsAggregationBuilder cat3nameTermsAggregationBuilder = AggregationBuilders.terms("cat3Agg").field("cat3name").size(30);

        // 6.2 設定過濾,過濾不會影響分數,過濾在bool中!!!!
        if (!StringUtils.isEmpty(searchDTO.getBrandNameFilter())) {
            // 不為空才設定
            TermQueryBuilder brandNameTermQueryBuilder = QueryBuilders.termQuery("brandName", searchDTO.getBrandNameFilter());
            // 系結到復合查詢中
            boolQueryBuilder.filter(brandNameTermQueryBuilder);
        }
        if (!StringUtils.isEmpty(searchDTO.getCat3NameFilter())) {
            // 不為空才設定
            TermQueryBuilder cat3namebrandNameTermQueryBuilder = QueryBuilders.termQuery("cat3name", searchDTO.getCat3NameFilter());
            // 系結到復合查詢中
            boolQueryBuilder.filter(cat3namebrandNameTermQueryBuilder);
        }

        // 7. 創建并設定查詢物件
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder()
                // 設定查詢條件,這里面已經設定了過濾了
                .withQuery(boolQueryBuilder)
                // 設定分頁條件
                .withPageable(pageRequest)
                // 設定高亮
                .withHighlightBuilder(getHighlightBuilder("goodsName"))
                // 設定聚合
                .addAggregation(brandNameTermsAggregationBuilder)
                .addAggregation(cat3nameTermsAggregationBuilder);

        // 8. 查詢
        SearchHits<ESGoods> search = restTemplate.search(nativeSearchQueryBuilder.build(), ESGoods.class);
        // 9. 設定總條數
        PageResult pageResultVO = new PageResult();
        pageResultVO.setTotal(search.getTotalHits());

        // 10. 獲取命中物件
        List<SearchHit<ESGoods>> searchHits = search.getSearchHits();
        // 11. 遍歷,處理每頁資料,和高亮
        List<ESGoods> esGoodsList = searchHits.stream().map(hit -> {
            // 獲取內容
            ESGoods esGoods = hit.getContent();
            // 設定高亮資訊
            Map<String, List<String>> highlightFields = hit.getHighlightFields();
            highlightFields.forEach((k, v) -> {
                // v 即是每個資訊中高亮的陣列屬性,做非空判斷
                if (v != null && v.size() > 0) {
                    // 如果k與域名相同,那么才設定高亮
                    if ("goodsName".equals(k)) {
                        esGoods.setGoodsName(v.get(0));
                    }
                }
            });
            return esGoods;
        }).collect(Collectors.toList());

        // 12. 從查詢結果中獲取聚合資訊
        Aggregations aggregations = search.getAggregations();
        // 從指定的域中獲取聚合的資訊
        Terms brandName = aggregations.get("brandAgg");
        Terms cat3name = aggregations.get("cat3Agg");
        // 獲取桶
        List<? extends Terms.Bucket> brandNameBuckets = brandName.getBuckets();
        List<? extends Terms.Bucket> cat3nameBuckets = cat3name.getBuckets();
        // 遍歷獲取
        List<String> brandNameList = brandNameBuckets.stream().map(item -> (String) item.getKey()).collect(Collectors.toList());
        pageResultVO.setBrandNameList(brandNameList);
        List<String> cat3NameList = cat3nameBuckets.stream().map(item -> (String) item.getKey()).collect(Collectors.toList());
        pageResultVO.setCat3NameList(cat3NameList);

        // 設定每頁資訊
        pageResultVO.setData(esGoodsList);
        return pageResultVO;
    }
    // 設定高亮欄位
    private HighlightBuilder getHighlightBuilder(String... fields) {
        // 高亮條件
        HighlightBuilder highlightBuilder = new HighlightBuilder(); //生成高亮查詢器
        for (String field : fields) {
            highlightBuilder.field(field);//高亮查詢欄位
        }
        highlightBuilder.requireFieldMatch(false);     //如果要多個欄位高亮,這項要為false
        highlightBuilder.preTags("<span style=\"color:red\">");   //高亮設定
        highlightBuilder.postTags("</span>");
        //下面這兩項,如果你要高亮如文字內容等有很多字的欄位,必須配置,不然會導致高亮不全,文章內容缺失等
        highlightBuilder.fragmentSize(800000); //最大高亮分片數
        highlightBuilder.numOfFragments(0); //從第一個分片獲取高亮片段

        return highlightBuilder;
    }
2.4.6 設定排序

對于排序,我們可以通過頁面原型發現,這里需要做的是對商品價格的排序

在查詢的DTO中插入排序的欄位String sortFilter,通過對傳入的欄位是asc還是desc來決定排序方式

這里需要注意的是:可能前端未傳入排序方式,那么此時就不需要在查詢中添加排序

回憶一下在kibana中我們是怎么使用排序的:
排序sort,和aggs聚合一樣與query同級,設定排序的欄位,order中設定排序方式,asc為升序,desc為降序
所以在代碼中的查詢中添加排序條件
  • 由此給出全部的查詢在kibana中的查詢陳述句,供參考和對比
GET es-goods/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "goodsName": "搶購"
          }
        },
        {
          "term": {
            "brandName": {
              "value": "良品鋪子"
            }
          }
        },
        {
          "term": {
            "cat3name": {
              "value": ""
            }
          }
        }
      ],
      "filter": [
        {
          "term": {
            "brandName": "百草味"
          }
        }
      ]
    }
  },
  "aggs": {
    "brandName_agg": {
      "terms": {
        "field": "brandName",
        "size": 10
      }
    },
    "cat3Name_agg":{
      "terms": {
        "field": "cat3name",
        "size": 10
      }
    }
  },
  "sort": [
    {
      "price": {
        "order": "desc"
      }
    }
  ]
}
  • 最終代碼實作:
@Override
    public PageResultVO<ESGoods> searchAndPageByES(SearchDTO searchDTO) {
        // 非空判斷
        if (searchDTO == null) {
            return new PageResultVO<>(false, "引數不合法");
        }
        // 從es中查詢
        // 1. 多重匹配查詢
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // 2. 條件匹配,需要分詞,匹配商品名稱,從條件dto中獲取,先做非空判斷
        if (!StringUtils.isEmpty(searchDTO.getKeyword())) {
            MatchQueryBuilder goodsName = QueryBuilders.matchQuery("goodsName", searchDTO.getKeyword());
            // 3. 條件匹配,不分詞,匹配品牌名稱
            TermQueryBuilder brandName = QueryBuilders.termQuery("brandName", searchDTO.getKeyword());
            // 4. 條件匹配 , 不分詞, 匹配3級分類名稱
            TermQueryBuilder cat3name = QueryBuilders.termQuery("cat3name", searchDTO.getKeyword());
            // 5. 使用should匹配,只要有一個符合就可以,這樣符合電商的性質
            boolQueryBuilder.should(goodsName).should(brandName).should(cat3name);
        }
        // 6. 設定分頁資訊,防止惡意攻擊
        if (searchDTO.getPage() <= 0 || searchDTO.getSize() <= 0) {
            searchDTO.setPage(1);
            searchDTO.setSize(5);
        }
        PageRequest pageRequest = PageRequest.of(searchDTO.getPage() - 1, searchDTO.getSize());

        // 6.1設定聚合
        TermsAggregationBuilder brandNameTermsAggregationBuilder = AggregationBuilders.terms("brandAgg").field("brandName").size(30);
        TermsAggregationBuilder cat3nameTermsAggregationBuilder = AggregationBuilders.terms("cat3Agg").field("cat3name").size(30);

        // 6.2 設定過濾,過濾不會影響分數,過濾在bool中!!!!
        if (!StringUtils.isEmpty(searchDTO.getBrandNameFilter())) {
            // 不為空才設置
            TermQueryBuilder brandNameTermQueryBuilder = QueryBuilders.termQuery("brandName", searchDTO.getBrandNameFilter());
            boolQueryBuilder.filter(brandNameTermQueryBuilder);
        }
        if (!StringUtils.isEmpty(searchDTO.getCat3NameFilter())) {
            // 不為空才設定
            TermQueryBuilder cat3namebrandNameTermQueryBuilder = QueryBuilders.termQuery("cat3name", searchDTO.getCat3NameFilter());
            boolQueryBuilder.filter(cat3namebrandNameTermQueryBuilder);
        }

        // 6.3 設定排序 , 排序與query同級
        // 提出變數,按條件賦值
        FieldSortBuilder price = null;
        if (!StringUtils.isEmpty(searchDTO.getSortField()) && "desc".equals(searchDTO.getSortField())) {
            // 不為空,且前端傳過來的是desc ,則按降序排列
            price = SortBuilders.fieldSort("price").order(SortOrder.DESC);
        }

        if (!StringUtils.isEmpty(searchDTO.getSortField()) && "asc".equals(searchDTO.getSortField())) {
            // 不為空,且前端傳過來的是desc ,則按降序排列
            price = SortBuilders.fieldSort("price").order(SortOrder.ASC);
        }

        // 7. 創建并設定查詢物件
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder()
                // 設定查詢條件
                .withQuery(boolQueryBuilder)
                // 設定分頁條件
                .withPageable(pageRequest)
                // 設定高亮
                .withHighlightBuilder(getHighlightBuilder("goodsName"))
                // 設定聚合
                .addAggregation(brandNameTermsAggregationBuilder)
                .addAggregation(cat3nameTermsAggregationBuilder);

        // 7.1 判斷排序條件是否存在
        if (price != null){
            // 存在則加上排序
            nativeSearchQueryBuilder.withSort(price);
        }

        // 8. 查詢
        SearchHits<ESGoods> search = restTemplate.search(nativeSearchQueryBuilder.build(), ESGoods.class);
        // 9. 設定總條數
        PageResult pageResultVO = new PageResult();
        pageResultVO.setTotal(search.getTotalHits());

        // 10. 獲取命中物件
        List<SearchHit<ESGoods>> searchHits = search.getSearchHits();
        // 11. 遍歷,處理每頁資料,和高亮
        List<ESGoods> esGoodsList = searchHits.stream().map(hit -> {
            // 獲取內容
            ESGoods esGoods = hit.getContent();
            // 設定高亮資訊
            Map<String, List<String>> highlightFields = hit.getHighlightFields();
            highlightFields.forEach((k, v) -> {
                // v 即是每個資訊中高亮的陣列屬性,做非空判斷
                if (v != null && v.size() > 0) {
                    // 如果k與域名相同,那么才設定高亮
                    if ("goodsName".equals(k)) {
                        esGoods.setGoodsName(v.get(0));
                    }
                }
            });
            return esGoods;
        }).collect(Collectors.toList());

        // 12. 從查詢結果中獲取聚合資訊
        Aggregations aggregations = search.getAggregations();
        // 從指定的域中獲取聚合的資訊
        Terms brandName = aggregations.get("brandAgg");
        Terms cat3name = aggregations.get("cat3Agg");
        // 獲取桶
        List<? extends Terms.Bucket> brandNameBuckets = brandName.getBuckets();
        List<? extends Terms.Bucket> cat3nameBuckets = cat3name.getBuckets();
        // 遍歷獲取
        List<String> brandNameList = brandNameBuckets.stream().map(item -> (String) item.getKey()).collect(Collectors.toList());
        pageResultVO.setBrandNameList(brandNameList);
        List<String> cat3NameList = cat3nameBuckets.stream().map(item -> (String) item.getKey()).collect(Collectors.toList());
        pageResultVO.setCat3NameList(cat3NameList);

        // 設定每頁資訊
        pageResultVO.setData(esGoodsList);
        return pageResultVO;
    }

	 // 設定高亮欄位
    private HighlightBuilder getHighlightBuilder(String... fields) {
        // 高亮條件
        HighlightBuilder highlightBuilder = new HighlightBuilder(); //生成高亮查詢器
        for (String field : fields) {
            highlightBuilder.field(field);//高亮查詢欄位
        }
        highlightBuilder.requireFieldMatch(false);     //如果要多個欄位高亮,這項要為false
        highlightBuilder.preTags("<span style=\"color:red\">");   //高亮設定
        highlightBuilder.postTags("</span>");
        //下面這兩項,如果你要高亮如文字內容等有很多字的欄位,必須配置,不然會導致高亮不全,文章內容缺失等
        highlightBuilder.fragmentSize(800000); //最大高亮分片數
        highlightBuilder.numOfFragments(0); //從第一個分片獲取高亮片段

        return highlightBuilder;
    }

至此,一個ElasticSearch的基本使用完成,你學廢了么?

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

標籤:其他

上一篇:java Spring Cloud+Spring boot+mybatis企業快速開發架構之云架構系統管理平臺

下一篇:hive資料庫及表操作

標籤雲
其他(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)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more