package com.search.supersearch;

import cn.hutool.json.JSONUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch.core.CountRequest;
import co.elastic.clients.elasticsearch.core.CountResponse;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.json.JsonData;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;

import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * 测试 elasticSearch search API 相关的操作
 *
 * @author WT
 * @date 2021/12/28 16:27:45
 */
@Slf4j
@SpringBootTest
@ActiveProfiles("wr") //这里
public class ElasticsearchClientSearchTest {

    private static final String INDEX_NAME = "elasticsearch-client";
    @Autowired
    private ElasticsearchClient elasticsearchClient;

    /**
     * 根据 name 查询相应的文档， search api 才是 elasticsearch-client 的优势，可以看出使用 lambda 大大简化了代码量，
     * 可以与 restHighLevelClient 形成鲜明的对比，但是也有可读性较差的问题，所以 lambda 的基础要扎实
     */
    @Test
    public void testRestClient() throws IOException {

        SearchResponse<Map> search = elasticsearchClient.search(s -> s.index(INDEX_NAME)
                        .query(q ->
                                q.term(t ->
                                        t.field("name").value(v -> v.stringValue("lisi1"))
                                )
                        ),
                Map.class);

        for (Hit<Map> hit : search.hits().hits()) {
            log.info("== hit: source: {}, id: {}", hit.source(), hit.id());
        }

    }

    // 多条件 返回查询
    @Test
    public void testMultipleCondition() throws IOException {

        SearchRequest request = SearchRequest.of(searchRequest ->
                searchRequest.index(INDEX_NAME).from(0).size(20).sort(s -> s.field(f -> f.field("age").order(SortOrder.Desc)))
                        // 如果有多个 .query 后面的 query 会覆盖前面的 query
                        .query(query ->
                                query.bool(boolQuery ->
                                        boolQuery
                                                // 在同一个 boolQuery 中 must 会将 should 覆盖
                                                .must(must -> must.range(
                                                        e -> e.field("age").gte(JsonData.of("21")).lte(JsonData.of("25"))
                                                ))
                                                .mustNot(mustNot -> mustNot.term(
                                                        e -> e.field("name").value(value -> value.stringValue("lisi1"))
                                                ))
                                                .should(must -> must.term(
                                                        e -> e.field("name").value(value -> value.stringValue("lisi2"))
                                                ))
                                )
                        )

        );

        SearchResponse<Map> searchResponse = elasticsearchClient.search(request, Map.class);


        log.info("返回的总条数有：{}", searchResponse.hits().total().value());
        List<Hit<Map>> hitList = searchResponse.hits().hits();
        for (Hit<Map> hit : hitList) {
            log.info("== hit: {}, id: {}", hit.source(), hit.id());
        }

    }

    // 多条件 返回查询
    @Test
    public void run() throws IOException {
        CountRequest request = CountRequest.of(searchRequest ->
                searchRequest.index("001001")
                        // 如果有多个 .query 后面的 query 会覆盖前面的 query
                        .query(q -> q.bool(b -> b
                                .should(s1 -> s1.matchPhrase(v -> v.field("content").query("用户已欠费")))
                                .should(s2 -> s2.matchPhrase(v -> v.field("filename").query("用户已欠费")))
                        ))

        );

        CountResponse count = elasticsearchClient.count(request);
        count.count();
        System.out.println(count.count());
        System.out.println(JSONUtil.toJsonStr(count));
    }
}
