1. 程式人生 > >ElasticSearch系列四 CURD

ElasticSearch系列四 CURD

1: ES 類似JPA操作

1.1 編寫實體類

1.2 編寫對映檔案 xxx.json

1.3編寫repository繼承 ElasticSearchrepository

1.4 編寫admin 的CRUD

2: 使用ElasticSearchtemplate 對索引操作

2.1 對索引的各類操作

3: 高階查詢

配置application

##es 單個ES地址 #spring.data.elasticsearch.cluster-nodes= ## 設定ES多個地址 
spring.data.elasticsearch.client.reactive.endpoints=[http://localhost:9200] ## 
開啟repositories spring.data.elasticsearch.repositories.enabled=true 
#spring.data.elasticsearch.client.reactive.connection-timeout= 
#spring.data.elasticsearch.client.reactive.password= 
#spring.data.elasticsearch.client.reactive.socket-timeout= 
#spring.data.elasticsearch.client.reactive.username= ##es  單個ES地址
#spring.data.elasticsearch.cluster-nodes=
##  設定ES多個地址
spring.data.elasticsearch.client.reactive.endpoints=[http://localhost:9200]
## 開啟repositories
spring.data.elasticsearch.repositories.enabled=true
#spring.data.elasticsearch.client.reactive.connection-timeout=
#spring.data.elasticsearch.client.reactive.password=
#spring.data.elasticsearch.client.reactive.socket-timeout=
#spring.data.elasticsearch.client.reactive.username=

pom依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

1: ES 類似JPA操作

1.1 編寫實體類

// indexName: 索引名稱  type: 執行資料庫型別的表
@Document(indexName = "esadmin",type = "admin")
@Mapping(mappingPath = "admin_es.json") //指向對映檔案
public class Admin {

    @Id
    private Long id;
    private String username;
    private String password;
    private String loveThings;
    // getter setter 方法

1.2 編寫對映檔案 xxx.json

{
  "properties": {
    "id": {
      "type": "long"
    },
    "username": {
      "type": "string",
      "index":    "not_analyzed"
    },
    "password": {
      "type": "string",
      "index":    "not_analyzed"
    },
    "loveThings": {
      "type": "text",
      "analyzer": "ik_max_word",
      "search_analyzer": "ik_max_word"
    }
  }
}

1.3編寫repository繼承 ElasticSearchrepository

@Repository public interface AdminRepository extends 
ElasticsearchRepository&lt;Admin,Long&gt; { }

1.4 編寫admin 的CRUD

@RestController
public class AdminController {

    @Autowired
    private AdminRepository adminRepository;

    // http://localhost:8080/saveOrUpdate

    /**
     *  send data
     * {
     *     "username":"dgw3",
     *     "password":"root",
     *     "loveThings":"postman(二):使用postman傳送get or post請"
     * }
     */
    @PostMapping("saveOrUpdate")
    public String saveOrUpdate(@RequestBody Admin admin){
        if(admin.getId()==null){
            admin.setId(System.currentTimeMillis());
        }
        adminRepository.save(admin);
        return "儲存成功";
    }
    //http://localhost:8080/delete?id=1582946734759
    @GetMapping("delete")
    public String delete(Long id){
        try {
            adminRepository.deleteById(id);
        } catch (Exception e) {
            e.printStackTrace();
            return "刪除失敗";
        }
        return "刪除成功";
    }
    //http://localhost:8080/findById?id=1582946734759
    @GetMapping("findById")
    public Admin findById(long id){
        Optional<Admin> admin = adminRepository.findById(id);
        if(admin.isPresent()){
            return admin.get();
        }else{
            return null;
        }
    }
    //http://localhost:8080/findAll
    @GetMapping("findAll")
    public Iterable<Admin> findAll(){
            return adminRepository.findAll();
    }
}

2: 使用ElasticSearchtemplate 對索引操作

2.1 對索引的各類操作

@RestController
public class ElasticOperationControler {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @GetMapping("createIndex")
    public boolean createIndex(String indexName){
        return elasticsearchTemplate.createIndex(indexName);
    }

    @GetMapping("deleteIndex")
    public boolean deleteIndex(String indexName){
        return elasticsearchTemplate.deleteIndex(indexName);
    }

    @GetMapping("indexIsExist")
    public boolean indexIsExist(String indexName){
        return elasticsearchTemplate.indexExists(indexName);
    }

    @GetMapping("typeIsExist")
    public boolean typeIsExist(String indexName,String type){
        return elasticsearchTemplate.typeExists(indexName,type);
    }

    @GetMapping("getMapping")
    public Map getMapping(String indexName, String type){
        return elasticsearchTemplate.getMapping(indexName,type);
    }

    @GetMapping("getSetting")
    public Map getSetting(String indexName){
        return elasticsearchTemplate.getSetting(indexName);
    }
}

3: 高階查詢

查詢步驟:

  • QueryBuilders 構建查詢關鍵詞
  • SortBuilders 構建對關鍵字的排序
  • NativeSearchQueryBuilder 對前兩個條件進行封裝,
  • Repository : 進行查詢
@RestController
public class SearchController {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @Autowired
    private ArticleRepository articleRepository;

    //1.不分詞查詢:查詢articleContent帶有你好 或者 articleName帶有你好的文章列表,並且按照readCount倒敘排序
    //http://localhost:8080/query1?keyword=你好
    @GetMapping("query1")
    public List<Article> query1(String keyword) {
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        BoolQueryBuilder articleContent = boolQuery.should(QueryBuilders.termQuery("articleContent", keyword));
        BoolQueryBuilder articleName = boolQuery.should(QueryBuilders.termQuery("articleName", keyword));

        FieldSortBuilder order = SortBuilders.fieldSort("readCount").order(SortOrder.DESC);

        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();

        nativeSearchQueryBuilder.withQuery(articleContent);
        nativeSearchQueryBuilder.withQuery(articleName);
        nativeSearchQueryBuilder.withSort(order);

        NativeSearchQuery searchQuery = nativeSearchQueryBuilder.build();

        Page<Article> articles = articleRepository.search(searchQuery);
        if (articles != null) {
            return articles.getContent();
        } else {
            return null;
        }
    }
    //2.不分詞查詢:查詢articleContent帶有我們 或者 你好 並且authorAge在20歲以下的文章列表,並且按照readCount倒敘排序
    //http://localhost:8080/query11?keyword=你好,我們
    @GetMapping("query2")
    public List<Article> query2(String... keyword) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.termsQuery("articleContent", keyword));
        boolQueryBuilder.must(QueryBuilders.rangeQuery("authorAge").lt(20));
        FieldSortBuilder fieldSortBuilder = SortBuilders.fieldSort("readCount").order(SortOrder.DESC);
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        nativeSearchQueryBuilder.withQuery(boolQueryBuilder);
        nativeSearchQueryBuilder.withSort(fieldSortBuilder);
        NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.build();
        Page<Article> page = articleRepository.search(nativeSearchQuery);
        if (page != null) {
            return page.getContent();
        } else {
            return null;
        }
    }

    //3.分詞查詢:經過分詞,查詢articleContent帶有你好節日一詞分詞後的文章列表,並且按照authorAge倒敘排序
    //http://localhost:8080/query12?keyword=你好節日
    @GetMapping("query3")
    public List<Article> query3(String keyword) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.should(QueryBuilders.matchQuery("articleContent", keyword));
        FieldSortBuilder fieldSortBuilder = SortBuilders.fieldSort("authorAge").order(SortOrder.DESC);
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        nativeSearchQueryBuilder.withQuery(boolQueryBuilder);
        nativeSearchQueryBuilder.withSort(fieldSortBuilder);
        NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.build();
        Page<Article> page = articleRepository.search(nativeSearchQuery);
        if (page != null) {
            return page.getContent();
        } else {
            return null;
        }
    }

    //4.分頁分詞查詢:經過分詞,查詢articleContent帶有你好節日一詞分詞後的文章列表,並且按照authorAge倒敘排序
    //http://localhost:8080/query13?keyword=你好節日&pageNum=1&pageSize=5
    @GetMapping("query4")
    public Page<Article> query4(String keyword, Integer pageNum, Integer pageSize) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.should(QueryBuilders.matchQuery("articleContent", keyword));
        FieldSortBuilder fieldSortBuilder = SortBuilders.fieldSort("authorAge").order(SortOrder.DESC);
        PageRequest pageRequest = new PageRequest(pageNum, pageSize);
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        nativeSearchQueryBuilder.withQuery(boolQueryBuilder);
        nativeSearchQueryBuilder.withSort(fieldSortBuilder);
        nativeSearchQueryBuilder.withPageable(pageRequest);
        NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.build();
        Page<Article> page = articleRepository.search(nativeSearchQuery);
        if (page != null) {
            return page;
        } else {
            return null;
        }
    }

    //5.分頁分詞查詢:經過分詞,查詢articleContent帶有你好節日一詞分詞後的文章列表,並且按照authorAge倒敘排序,並且對匹配到的詞語設定為高亮
    //http://localhost:8080/query14?keyword=你好節日&pageNum=1&pageSize=5&fieldNames=articleContent,articleName
    @GetMapping("query5")
    public Map<String, Object> query5(String keyword, Integer pageNum, Integer pageSize, String... fieldNames) {

        //定義返回的map
        Map<String, Object> returnMap = new HashMap<String,Object>();

        // 不使用預設的分詞器  直接操控索引
        //構建請求構建器,設定查詢索引
        SearchRequestBuilder builder = elasticsearchTemplate.getClient().prepareSearch("testes");

        //構建查詢構建器,設定分詞器(如果沒設定使用預設)
        QueryBuilder matchQuery = QueryBuilders.multiMatchQuery(keyword, fieldNames).analyzer("ik_max_word");

        //構建高亮構建器
        HighlightBuilder highlightBuilder = new HighlightBuilder().field("*").requireFieldMatch(false);
        highlightBuilder.preTags("<span style=\"color:red\">");
        highlightBuilder.postTags("</span>");

        //將高亮構建器,查詢構建器,分頁引數設定到請求構建器內
        builder.highlighter(highlightBuilder);
        builder.setQuery(matchQuery);
        builder.setFrom((pageNum - 1) * pageSize);
        builder.setSize(pageNum * pageSize);
        builder.setSize(pageSize);

        //執行搜尋,返回搜尋響應資訊
        SearchResponse searchResponse = builder.get();
        SearchHits searchHits = searchResponse.getHits();

        //總命中數
        long total = searchHits.getTotalHits();
        returnMap.put("count", total);

        //將高亮欄位封裝到返回map
        SearchHit[] hits = searchHits.getHits();
        List<Map<String,Object>> list = new ArrayList<>();
        Map<String,Object> map;
        for(SearchHit searchHit : hits){
            map = new HashMap<>();
            map.put("data",searchHit.getSourceAsMap());
            Map<String,Object> hitMap = new HashMap<>();
            searchHit.getHighlightFields().forEach((k,v) -> {
                String hight = "";
                for(Text text : v.getFragments()){
                    hight += text.string();
                }
                hitMap.put(v.getName(),hight);
            });
            map.put("highlight",hitMap);
            list.add(map);
        }
        returnMap.put("dataList", list);
        return returnMap;
    }