Elasticsearch Java高級客戶端

1.  概述css

Java REST Client 有兩種風格:html

  • Java Low Level REST Client :用於Elasticsearch的官方低級客戶端。它容許經過http與Elasticsearch集羣通訊。將請求編排和響應反編排留給用戶本身處理。它兼容全部的Elasticsearch版本。(PS:學過WebService的話,對編排與反編排這個概念應該不陌生。能夠理解爲對請求參數的封裝,以及對響應結果的解析)
  • Java High Level REST Client :用於Elasticsearch的官方高級客戶端。它是基於低級客戶端的,它提供不少API,並負責請求的編排與響應的反編排。(PS:就比如是,一個是傳本身拼接好的字符串,而且本身解析返回的結果;而另外一個是傳對象,返回的結果也已經封裝好了,直接是對象,更加規範了參數的名稱以及格式,更加面對對象一點)

(PS:所謂低級與高級,我以爲一個很形象的比喻是,面向過程編程與面向對象編程)java

在 Elasticsearch 7.0 中不建議使用TransportClient,而且在8.0中會徹底刪除TransportClient。所以,官方更建議咱們用Java High Level REST Client,它執行HTTP請求,而不是序列號的Java請求。既然如此,這裏就直接用高級了。jquery

 

2.  Java High Level REST Client (高級REST客戶端)git

2.1.  Maven倉庫github

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

2.2.  依賴web

  • org.elasticsearch.client:elasticsearch-rest-client
  • org.elasticsearch:elasticsearch

2.3.  初始化spring

RestHighLevelClient client = new RestHighLevelClient(
        RestClient.builder(
                new HttpHost("localhost", 9200, "http"),
                new HttpHost("localhost", 9201, "http")));

高級客戶端內部會建立低級客戶端用於基於提供的builder執行請求。低級客戶端維護一個鏈接池,並啓動一些線程,所以當你用完之後應該關閉高級客戶端,而且在內部它將會關閉低級客戶端,以釋放這些資源。關閉客戶端可使用close()方法:apache

client.close();

 

2.4.  文檔API編程

2.4.1.  添加文檔

IndexRequest

IndexRequest request = new IndexRequest("posts", "doc", "1");
String jsonString = "{\"user\":\"kimchy\",\"postDate\":\"2013-01-30\",\"message\":\"trying out Elasticsearch\"}";
request.source(jsonString, XContentType.JSON);

提供文檔source的方式還有不少,好比:

經過Map的方式提供文檔source

經過XContentBuilder方式提供source

經過Object的方式(鍵值對)提供source

可選參數

同步執行

異步執行

你也能夠異步執行 IndexRequest,爲此你須要指定一個監聽器來處理這個異步響應結果:

一個典型的監聽器看起來是這樣的:

IndexResponse

若是有版本衝突,將會拋出ElasticsearchException

一樣的異常也有可能發生在當opType設置爲create的時候,且相同索引、相同類型、相同ID的文檔已經存在時。例如:

 

2.4.2.  查看文檔

Get Request

可選參數

同步執行

異步執行

Get Response

當索引不存在,或者指定的文檔的版本不存在時,響應狀態嗎是404,而且拋出ElasticsearchException

 

2.4.3.  文檔是否存在

 

2.4.4.  刪除文檔

Delete Request

可選參數

同添加

 

2.5.  搜索API

Search Request

基本格式是這樣的:

大多數查詢參數被添加到 SearchSourceBuilder

可選參數

SearchSourceBuilder

控制檢索行爲的大部分選項均可以在SearchSourceBuilder中設置。下面是一個常見選項的例子:

在這個例子中,咱們首先建立了一個SearchSourceBuilder對象,而且帶着默認選項。而後設置了一個term查詢,接着設置檢索的位置和數量,最後設置超時時間

在設置完這些選項之後,咱們只須要把SearchSourceBuilder加入到SearchRequest中便可

 

構建Query

用QueryBuilder來建立Serarch Query。QueryBuilder支持Elasticsearch DSL中每一種Query

例如:

還能夠經過QueryBuilders工具類來建立QueryBuilder對象,例如:

不管是用哪一種方式建立,最後必定要把QueryBuilder添加到SearchSourceBuilder中

 

排序

SearchSourceBuilder 能夠添加一個或多個 SortBuilder

SortBuilder有四種實現:FieldSortBuilder、GeoDistanceSortBuilder、ScoreSortBuilder、ScriptSortBuilder

 

彙集函數

同步執行

異步執行

從查詢響應中取出文檔

 

3.  示例

3.1.  準備數據

3.1.1.  安裝IK分詞器插件

./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.5.4/elasticsearch-analysis-ik-6.5.4.zip

3.1.2.  建立索引

curl -X PUT "localhost:9200/book" -H 'Content-Type: application/json' -d'
{
    "mappings":{
        "_doc":{
            "properties":{
                "id":{
                    "type":"integer"
                },
                "name":{
                    "type":"text",
                    "analyzer":"ik_max_word",
                    "search_analyzer":"ik_max_word"
                },
                "author":{
                    "type":"text",
                    "analyzer":"ik_max_word",
                    "search_analyzer":"ik_max_word"
                },
                "category":{
                    "type":"integer"
                },
                "price":{
                    "type":"double"
                },
                "status":{
                    "type":"short"
                },
                "sellReason":{
                    "type":"text",
                    "analyzer":"ik_max_word",
                    "search_analyzer":"ik_max_word"
                },
                "sellTime":{
                    "type":"date",
                    "format":"yyyy-MM-dd"
                }
            }
        }
    }
}
'

3.1.3.  數據預覽

 

3.2.  示例代碼

3.2.1.  完整的pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.cjs.example</groupId>
    <artifactId>elasticsearch-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>elasticsearch-demo</name>
    <description></description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.8</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.54</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

3.2.2.  配置

package com.cjs.example.elasticsearch.config;

import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author ChengJianSheng
 * @date 2019-01-07
 */
@Configuration
public class ElasticsearchClientConfig {

    @Bean
    public RestHighLevelClient restHighLevelClient() {
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("localhost", 9200, "http")));
        return client;
    }

}

3.2.3.  domain

package com.cjs.example.elasticsearch.domain.model;

import lombok.Data;

import java.io.Serializable;

/**
 * 圖書
 * @author ChengJianSheng
 * @date 2019-01-07
 */
@Data
public class BookModel implements Serializable {


    private Integer id;         //  圖書ID

    private String name;        //  圖書名稱

    private String author;      //  做者

    private Integer category;   //  圖書分類

    private Double price;       //  圖書價格

    private String sellReason;  //  上架理由

    private String sellTime;      //  上架時間

    private Integer status;     //  狀態(1:可售,0:不可售)

}

3.2.4.  Controller

package com.cjs.example.elasticsearch.controller;

import com.alibaba.fastjson.JSON;
import com.cjs.example.elasticsearch.domain.common.BaseResult;
import com.cjs.example.elasticsearch.domain.common.Page;
import com.cjs.example.elasticsearch.domain.model.BookModel;
import com.cjs.example.elasticsearch.domain.vo.BookRequestVO;
import com.cjs.example.elasticsearch.service.BookService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * 文檔操做
 * @author ChengJianSheng
 * @date 2019-01-07
 */
@Slf4j
@RestController
@RequestMapping("/book")
public class BookController {

    @Autowired
    private BookService bookService;

    /**
     * 列表分頁查詢
     */
    @GetMapping("/list")
    public BaseResult list(BookRequestVO bookRequestVO) {
        Page<BookModel> page = bookService.list(bookRequestVO);
        if (null == page) {
            return BaseResult.error();
        }
        return BaseResult.ok(page);
    }

    /**
     * 查看文檔
     */
    @GetMapping("/detail")
    public BaseResult detail(Integer id) {
        if (null == id) {
            return BaseResult.error("ID不能爲空");
        }
        BookModel book = bookService.detail(id);
        return BaseResult.ok(book);
    }

    /**
     * 添加文檔
     */
    @PostMapping("/add")
    public BaseResult add(@RequestBody BookModel bookModel) {
        bookService.save(bookModel);
        log.info("插入文檔成功!請求參數: {}", JSON.toJSONString(bookModel));
        return BaseResult.ok();
    }

    /**
     * 修改文檔
     */
    @PostMapping("/update")
    public BaseResult update(@RequestBody BookModel bookModel) {
        Integer id = bookModel.getId();
        if (null == id) {
            return BaseResult.error("ID不能爲空");
        }
        BookModel book = bookService.detail(id);
        if (null == book) {
            return BaseResult.error("記錄不存在");
        }
        bookService.update(bookModel);
        log.info("更新文檔成功!請求參數: {}", JSON.toJSONString(bookModel));
        return BaseResult.ok();
    }

    /**
     * 刪除文檔
     */
    @GetMapping("/delete")
    public BaseResult delete(Integer id) {
        if (null == id) {
            return BaseResult.error("ID不能爲空");
        }
        bookService.delete(id);
        return BaseResult.ok();
    }

}

3.2.5.  Service

package com.cjs.example.elasticsearch.service.impl;

import com.alibaba.fastjson.JSON;
import com.cjs.example.elasticsearch.domain.common.Page;
import com.cjs.example.elasticsearch.domain.model.BookModel;
import com.cjs.example.elasticsearch.domain.vo.BookRequestVO;
import com.cjs.example.elasticsearch.service.BookService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.replication.ReplicationResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ChengJianSheng
 * @date 2019-01-07
 */
@Slf4j
@Service
public class BookServiceImpl implements BookService {

    private static final String INDEX_NAME = "book";
    private static final String INDEX_TYPE = "_doc";

    @Autowired
    private RestHighLevelClient client;


    @Override
    public Page<BookModel> list(BookRequestVO bookRequestVO) {
        int pageNo = bookRequestVO.getPageNo();
        int pageSize = bookRequestVO.getPageSize();

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.from(pageNo - 1);
        sourceBuilder.size(pageSize);
        sourceBuilder.sort(new FieldSortBuilder("id").order(SortOrder.ASC));
//        sourceBuilder.query(QueryBuilders.matchAllQuery());

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        if (StringUtils.isNotBlank(bookRequestVO.getName())) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("name", bookRequestVO.getName()));
        }
        if (StringUtils.isNotBlank(bookRequestVO.getAuthor())) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("author", bookRequestVO.getAuthor()));
        }
        if (null != bookRequestVO.getStatus()) {
            boolQueryBuilder.must(QueryBuilders.termQuery("status", bookRequestVO.getStatus()));
        }
        if (StringUtils.isNotBlank(bookRequestVO.getSellTime())) {
            boolQueryBuilder.must(QueryBuilders.termQuery("sellTime", bookRequestVO.getSellTime()));
        }
        if (StringUtils.isNotBlank(bookRequestVO.getCategories())) {
            String[] categoryArr = bookRequestVO.getCategories().split(",");
            List<Integer> categoryList = Arrays.asList(categoryArr).stream().map(e->Integer.valueOf(e)).collect(Collectors.toList());
            BoolQueryBuilder categoryBoolQueryBuilder = QueryBuilders.boolQuery();
            for (Integer category : categoryList) {
                categoryBoolQueryBuilder.should(QueryBuilders.termQuery("category", category));
            }
            boolQueryBuilder.must(categoryBoolQueryBuilder);
        }

        sourceBuilder.query(boolQueryBuilder);

        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(INDEX_NAME);
        searchRequest.source(sourceBuilder);

        try {
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);

            RestStatus restStatus = searchResponse.status();
            if (restStatus != RestStatus.OK) {
                return null;
            }

            List<BookModel> list = new ArrayList<>();
            SearchHits searchHits = searchResponse.getHits();
            for (SearchHit hit : searchHits.getHits()) {
                String source = hit.getSourceAsString();
                BookModel book = JSON.parseObject(source, BookModel.class);
                list.add(book);
            }

            long totalHits = searchHits.getTotalHits();

            Page<BookModel> page = new Page<>(pageNo, pageSize, totalHits, list);

            TimeValue took = searchResponse.getTook();
            log.info("查詢成功!請求參數: {}, 用時{}毫秒", searchRequest.source().toString(), took.millis());

            return page;
        } catch (IOException e) {
            log.error("查詢失敗!緣由: {}", e.getMessage(), e);
        }

        return null;
    }

    @Override
    public void save(BookModel bookModel) {
        Map<String, Object> jsonMap = new HashMap<>();
        jsonMap.put("id", bookModel.getId());
        jsonMap.put("name", bookModel.getName());
        jsonMap.put("author", bookModel.getAuthor());
        jsonMap.put("category", bookModel.getCategory());
        jsonMap.put("price", bookModel.getPrice());
        jsonMap.put("sellTime", bookModel.getSellTime());
        jsonMap.put("sellReason", bookModel.getSellReason());
        jsonMap.put("status", bookModel.getStatus());

        IndexRequest indexRequest = new IndexRequest(INDEX_NAME, INDEX_TYPE, String.valueOf(bookModel.getId()));
        indexRequest.source(jsonMap);

        client.indexAsync(indexRequest, RequestOptions.DEFAULT, new ActionListener<IndexResponse>() {
            @Override
            public void onResponse(IndexResponse indexResponse) {
                String index = indexResponse.getIndex();
                String type = indexResponse.getType();
                String id = indexResponse.getId();
                long version = indexResponse.getVersion();

                log.info("Index: {}, Type: {}, Id: {}, Version: {}", index, type, id, version);

                if (indexResponse.getResult() == DocWriteResponse.Result.CREATED) {
                    log.info("寫入文檔");
                } else if (indexResponse.getResult() == DocWriteResponse.Result.UPDATED) {
                    log.info("修改文檔");
                }
                ReplicationResponse.ShardInfo shardInfo = indexResponse.getShardInfo();
                if (shardInfo.getTotal() != shardInfo.getSuccessful()) {
                    log.warn("部分分片寫入成功");
                }
                if (shardInfo.getFailed() > 0) {
                    for (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) {
                        String reason = failure.reason();
                        log.warn("失敗緣由: {}", reason);
                    }
                }
            }

            @Override
            public void onFailure(Exception e) {
                log.error(e.getMessage(), e);
            }
        });
    }

    @Override
    public void update(BookModel bookModel) {
        Map<String, Object> jsonMap = new HashMap<>();
        jsonMap.put("sellReason", bookModel.getSellReason());
        UpdateRequest request = new UpdateRequest(INDEX_NAME, INDEX_TYPE, String.valueOf(bookModel.getId()));
        request.doc(jsonMap);
        try {
            UpdateResponse updateResponse = client.update(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("更新失敗!緣由: {}", e.getMessage(), e);
        }
    }

    @Override
    public void delete(int id) {
        DeleteRequest request = new DeleteRequest(INDEX_NAME, INDEX_TYPE, String.valueOf(id));
        try {
            DeleteResponse deleteResponse = client.delete(request, RequestOptions.DEFAULT);
            if (deleteResponse.status() == RestStatus.OK) {
                log.info("刪除成功!id: {}", id);
            }
        } catch (IOException e) {
            log.error("刪除失敗!緣由: {}", e.getMessage(), e);
        }
    }

    @Override
    public BookModel detail(int id) {
        GetRequest getRequest = new GetRequest(INDEX_NAME, INDEX_TYPE, String.valueOf(id));
        try {
            GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT);
            if (getResponse.isExists()) {
                String source = getResponse.getSourceAsString();
                BookModel book = JSON.parseObject(source, BookModel.class);
                return book;
            }
        } catch (IOException e) {
            log.error("查看失敗!緣由: {}", e.getMessage(), e);
        }
        return null;
    }
}

3.2.6.  頁面

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>圖書列表</title>

    <link rel="stylesheet" href="/bootstrap-4/css/bootstrap.min.css">
    <link rel="stylesheet" href="/bootstrap-table/bootstrap-table.css">

    <script src="jquery-3.3.1.min.js"></script>
    <script src="/bootstrap-4/js/bootstrap.min.js"></script>
    <script src="/bootstrap-table/bootstrap-table.js"></script>
    <script src="/bootstrap-table/locale/bootstrap-table-zh-CN.js"></script>
    <script>
        $(function(){

            $('#table').bootstrapTable({
                url: '/book/list',
                method: 'get',
                sidePagination: 'server',
                responseHandler: function(res) {  // 加載服務器數據以前的處理程序,能夠用來格式化數據。參數:res爲從服務器請求到的數據。
                    var result = {};
                    result.total = res.data.totalCount;
                    result.rows = res.data.pageList;
                    return result;
                },
                pagination: true,
                pageSize: 3, // 初始PageSize
                queryParams: function(params) {
                    var req = {
                        pageSize: params.limit,
                        pageNo: params.offset + 1
                    };
                    return req;
                },
                striped: true,
                search: true,
                columns: [{
                    field: 'id',
                    title: 'ID'
                }, {
                    field: 'name',
                    title: '名稱'
                }, {
                    field: 'author',
                    title: '做者'
                }, {
                    field: 'price',
                    title: '單價'
                }, {
                    field: 'sellTime',
                    title: '上架時間'
                }, {
                    field: 'status',
                    title: '狀態',
                    formatter: function(value) {
                        if (value == 1) {
                            return '<span style="color: green">可售</span>';
                        } else {
                            return '<span style="color: red">不可售</span>';
                        }
                    }
                }, {
                    field: 'category',
                    title: '分類',
                    formatter: function(value) {
                        if (value == 10010) {
                            return '中國當代小說';
                        } else if (value == 10011) {
                            return '武俠小說';
                        } else if (value == 10012) {
                            return '愛情小說';
                        } else if (value == 10013) {
                            return '中國當代隨筆';
                        }
                    }
                }, {
                    field: 'sellReason',
                    title: '上架理由'
                }, {
                    title: '操做',
                    formatter: function() {
                        return '<a href="#">修改</a> <a href="#">刪除</a>';
                    }
                }
                ]
            });

        });
    </script>
</head>
<body>
    <div class="table-responsive" style="padding: 10px 30px">
        <table id="table" class="table text-nowrap"></table>
    </div>
</body>
</html>

3.3.  演示

重點演示幾個查詢

返回結果:

{
    "code": 200,
    "success": true,
    "msg": "SUCCESS",
    "data": {
        "pageNumber": 1,
        "pageSize": 10,
        "totalCount": 2,
        "pageList": [
            {
                "id": 2,
                "name": "倚天屠龍記(全四冊)",
                "author": "金庸",
                "category": 10011,
                "price": 70.4,
                "sellReason": "武林至尊,寶刀屠龍,號令天下,莫敢不從。",
                "sellTime": "2018-11-11",
                "status": 1
            },
            {
                "id": 3,
                "name": "神鵰俠侶",
                "author": "金庸",
                "category": 10011,
                "price": 70,
                "sellReason": "風陵渡口初相遇,一見楊過誤終身",
                "sellTime": "2018-11-11",
                "status": 1
            }
        ]
    }
}

上面的查詢對應的Elasticsearch DSL是這樣的:

{
    "from":0,
    "size":10,
    "query":{
        "bool":{
            "must":[
                {
                    "match":{
                        "author":{
                            "query":"金庸",
                            "operator":"OR",
                            "prefix_length":0,
                            "max_expansions":50,
                            "fuzzy_transpositions":true,
                            "lenient":false,
                            "zero_terms_query":"NONE",
                            "auto_generate_synonyms_phrase_query":true,
                            "boost":1
                        }
                    }
                },
                {
                    "term":{
                        "status":{
                            "value":1,
                            "boost":1
                        }
                    }
                },
                {
                    "bool":{
                        "should":[
                            {
                                "term":{
                                    "category":{
                                        "value":10010,
                                        "boost":1
                                    }
                                }
                            },
                            {
                                "term":{
                                    "category":{
                                        "value":10011,
                                        "boost":1
                                    }
                                }
                            },
                            {
                                "term":{
                                    "category":{
                                        "value":10012,
                                        "boost":1
                                    }
                                }
                            }
                        ],
                        "adjust_pure_negative":true,
                        "boost":1
                    }
                }
            ],
            "adjust_pure_negative":true,
            "boost":1
        }
    },
    "sort":[
        {
            "id":{
                "order":"asc"
            }
        }
    ]
}

3.4.  工程結構

 

4.  參考

https://github.com/medcl/elasticsearch-analysis-ik

https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high.html

https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high-search.html

https://bootstrap-table.wenzhixin.net.cn/documentation/

 

5.  其它相關

Elasticsearch 分詞器

Elasticsearch Document

Elasticsearch Search API

Elasticsearch查詢

Elasticsearch Mapping

SpringBoot+Elasticsearch

ELK快速搭建日誌平臺

相關文章
相關標籤/搜索