七、黑马程序员酒店demo之文档搜索RestAPI单元测试

文末附上项目的下载地址

第五章节中含有一些文档的搜索等操作,这里是基于黑马程序员的搜索做的一次单元测试,单元测试类如下,下一章节将整个项目的java文件贴出

文档搜索RestAPI单元测试

package com.toto.es.hotel;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.DistanceUnit;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
import co.elastic.clients.elasticsearch._types.aggregations.BucketMetricValueAggregate;
import co.elastic.clients.elasticsearch._types.aggregations.Buckets;
import co.elastic.clients.elasticsearch._types.aggregations.StringTermsBucket;
import co.elastic.clients.elasticsearch._types.query_dsl.*;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.CompletionSuggest;
import co.elastic.clients.elasticsearch.core.search.CompletionSuggestOption;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.Suggestion;
import co.elastic.clients.json.JsonData;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import co.elastic.clients.util.NamedValue;
import co.elastic.clients.util.ObjectBuilder;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.toto.es.hotel.pojo.HotelDoc;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Description: HotelSearchTest
 * @Package: com.toto.es.hotel
 * @Author gufanbiao
 * @CreateTime 2024-05-04 10:43
 */
@SpringBootTest
@SuppressWarnings("all")
public class HotelSearchTest {
    private RestClient restClient;
    private ElasticsearchClient client;
    private ElasticsearchTransport transport;

    /**
     * 查询所有文档
     */
    @Test
    void testSearchAll() throws IOException {
        SearchResponse<HotelDoc> response = client.search(builder -> builder.index("hotel"), HotelDoc.class);
        handleResponse(response);
    }

    /**
     * match 根据字段查询
     */
    @Test
    void testMatch() throws IOException {
        SearchResponse<HotelDoc> response = client.search(builder -> builder.index("hotel").query(query -> query.match(match -> match.field("all").query("如家"))), HotelDoc.class);
        handleResponse(response);
    }

    /**
     * 多id查询
     * @param response
     */
    @Test
    void testMultiId() throws IOException {
        SearchResponse<HotelDoc> response = client.search(builder -> builder.index("hotel").query(query -> query.ids(ids -> ids.values("728604", "441836", "433576"))), HotelDoc.class);
        handleResponse(response);
    }

    /**
     * term 不分词查询(精确)
     * @param response
     */
    @Test
    void testTerm() throws IOException {
        SearchResponse<HotelDoc> response = client.search(builder -> builder.index("hotel").query(query -> query.term(term -> term.field("city").value("北京"))), HotelDoc.class);
        handleResponse(response);
    }

    /**
     * 范围查询
     * @param response
     */
    @Test
    void testRange() throws IOException {
        SearchResponse<HotelDoc> response = client.search(builder -> builder.index("hotel").query(query -> query.range(range -> range.field("price").gte(JsonData.of(200)).lte(JsonData.of(1000)))), HotelDoc.class);
        handleResponse(response);
    }

    /**
     * 前缀查询
     * @param response
     */
    @Test
    void testPrefix() throws IOException {
        SearchResponse<HotelDoc> response = client.search(builder -> builder.index("hotel").query(query -> query.prefix(prefix -> prefix.field("brand").value("如"))), HotelDoc.class);
        handleResponse(response);
    }

    /**
     * 匹配查询
     * @param response
     */
    @Test
    void testMatchPhrase() throws IOException {
        //SearchResponse<HotelDoc> response = client.search(builder -> builder.index("hotel").query(query -> query.matchPhrase(matchPhrase -> matchPhrase.field("all").query("如家"))), HotelDoc.class);
        SearchResponse<HotelDoc> response = client.search(builder -> builder.index("hotel").query(query -> query.wildcard(w->w.field("name").value("如*"))), HotelDoc.class);
        handleResponse(response);
    }

    /**
     * 匹配查询 ?单字符匹配
     */
    @Test
    void testMatchPhrase2() throws IOException {
        //SearchResponse<HotelDoc> response = client.search(builder -> builder.index("hotel").query(query -> query.matchPhrase(matchPhrase -> matchPhrase.field("all").query("如家?"))), HotelDoc.class);
        SearchResponse<HotelDoc> response = client.search(builder -> builder.index("hotel").query(query -> query.wildcard(w->w.field("all").value("?家"))), HotelDoc.class);
        handleResponse(response);
    }

    /**
     * 模糊查询
     * @param response
     */
    @Test
    void testFuzzy() throws IOException {
        SearchResponse<HotelDoc> response = client.search(builder -> builder.index("hotel").query(query -> query.fuzzy(fuzzy -> fuzzy.field("all").value("如家"))), HotelDoc.class);
        handleResponse(response);
    }

    /**
     * 多条件查询
     * must:所有条件必须同时成立
     * must_not:所有条件必须同时不成立
     * should:所有条件中成立一个即可
     * @param response
     */
    @Test
    void testMulti() throws IOException {
        SearchResponse<HotelDoc> response = client.search(builder -> builder.index("hotel").query(query ->
                query.bool(bool ->
                        bool.must(must -> must.match(match -> match.field("all").query("如家")))
                                .filter(filter -> filter.term(term -> term.field("city").value("北京"))))), HotelDoc.class);
        handleResponse(response);
    }

    /**
     * 多字段查询-multiMatch
     * @param response
     */
    @Test
    void testMultiMatch() throws IOException {
        SearchResponse<HotelDoc> response = client.search(builder -> builder.index("hotel").query(query ->
                query.multiMatch(multiMatch -> multiMatch.fields("all", "brand").query("如家 汉庭"))), HotelDoc.class);
        handleResponse(response);
    }

    /**
     * 高亮显示
     * @param response
     */
    @Test
    void testHighlight() throws IOException {
        //SearchResponse<HotelDoc> response = client.search(builder -> builder.index("hotel").query(query -> query.match(match -> match.field("all").query("如家"))).highlight(highlight -> highlight.fields("all", highlightFields -> highlightFields.highlighter(highlighter -> highlighter.type("fvh")))), HotelDoc.class);
        SearchResponse<HotelDoc> response = client.search(builder ->
                        builder.index("hotel")
                                .query(query -> query.match(match -> match.field("all").query("汉庭")))
                                .highlight(highlight -> highlight
                                        .fields("name", hf -> hf.requireFieldMatch(false))
                                        .preTags("<span>")
                                        .postTags("</span>")),
                HotelDoc.class);
        handleResponse(response);
    }

    /**
     * 分页查询
     * @param response
     */
    @Test
    void testPage() throws IOException {
        SearchResponse<HotelDoc> response = client.search(builder -> builder.index("hotel")
                .query(query -> query.match(match -> match.field("all").query("如家")))
                .from(0)
                .size(200)
                .trackTotalHits(t->t.enabled(true)), //使用分页时,最多返回10000条。需要进行设置
            HotelDoc.class);
        handleResponse(response);
    }

    /**
     * 排序
     * @throws IOException
     */
    @Test
    void testSort() throws IOException {
        SearchResponse<HotelDoc> response = client.search(builder -> builder.index("hotel")
                .query(query -> query.match(match -> match.field("all").query("如家")))
                .sort(sort -> sort.field(fieldSort -> fieldSort.field("price").order(SortOrder.Asc))), HotelDoc.class);
        handleResponse(response);
    }

    /**
     * 指定字段查询 filter去指定是include包含或是exclude去除xx字段
     * @param response
     */
    @Test
    void testField() throws IOException {
        SearchResponse<HotelDoc> response = client.search(builder ->
                        builder.index("hotel")
                                .query(q->q.matchAll(v->v))
                                .source(s->s.filter(v->v.includes("price","brand", "name"))),
                HotelDoc.class);
        handleResponse(response);
    }

    /**
     * 地理坐标排序
     * @param response
     */
    @Test
    void testGeoSort() throws IOException {
        SearchResponse<HotelDoc> response = client.search(builder ->
                        builder.index("hotel")
                                .query(query -> query.matchAll(v->v))
                                .sort(sort -> sort.geoDistance(geo -> geo.field("location").location(l -> l.latlon(ll -> ll.lat(31.034661).lon(121.612282))).unit(DistanceUnit.Kilometers).order(SortOrder.Asc))),
                HotelDoc.class);
        handleResponse(response);
    }

    /**
     * 组合查询 function score 
     * @param response
     */
    @Test
    void testFunctionScore() throws IOException {
        BoolQuery.Builder boolQuery = QueryBuilders.bool();
        boolQuery.must(must -> must.match(match -> match.field("name").query("万丽")));
        SearchResponse<HotelDoc> response = client.search(builder ->
                        builder.index("hotel")
                                //.query(query -> query.bool(bool -> bool.must(must -> must.match(match -> match.field("all").query("如家")))))
                                .query(query -> query
                                        .functionScore(fs -> fs
                                                // 原始查询,相关性算分的查询
                                                //.query(q -> q.match(match -> match.field("name").query("万丽")))
                                                .query(q -> q.bool(b -> boolQuery))
                                                // 算分函数和过滤条件
                                                .functions(fsFunctions -> fsFunctions.filter(f -> f.term(t -> t.field("isAD").value(true))).weight(10D))
                                                // 加权模式
                                                .boostMode(FunctionBoostMode.Multiply))),
                HotelDoc.class);
        handleResponse(response);
    }

    /**
     * 聚合查询 对品牌、城市、品牌、价格等维度进行聚合统计
     * Buckets<LongTermsBucket> longBuckets = aggregate.lterms().buckets();
     * Buckets<StringTermsBucket> stringBuckets = aggregate.sterms().buckets();
     * Buckets<DoubleTermsBucket> doubleBuckets = aggregate.dterms().buckets();
     * @param response
     */
    @Test
    void testAgg() throws IOException, InterruptedException {
        SearchResponse<Map> response = client.search(builder ->
                        builder.index("hotel")
                                .size(0)
                                .aggregations("brandAgg", a -> a.terms(t -> t.field("brand").size(30))),
                Map.class);
        Map<String, Aggregate> aggregations = response.aggregations();
        Aggregate brandAgg = aggregations.get("brandAgg");
        Buckets<StringTermsBucket> buckets = brandAgg.sterms().buckets();
        for (StringTermsBucket b : buckets.array()) {
            System.err.println(b.key().stringValue() + " : " + b.docCount());
        }
    }

    /**
     * Bucket聚合功能,自定义排序规则
     * @param response
     */
    @Test
    void testAggSort() throws IOException {
        SearchResponse<HotelDoc> response = client.search(builder ->
                        builder.index("hotel")
                                .size(0)
                                .aggregations("brand_agg", a -> a.terms(t -> t.field("brand").size(2).order(new NamedValue<>("_count", SortOrder.Desc)))),
                HotelDoc.class);
        System.err.println(response);
        handleResponse(response);
    }

    /**
     * Bucket聚合功能,限定聚合范围
     * @param response
     */
    @Test
    void testAggRange() throws IOException {
        SearchResponse<HotelDoc> response = client.search(builder ->
                        builder.index("hotel")
                                .query(q -> q.range(r -> r.field("price").gte(JsonData.of(0)).lte(JsonData.of(300))))
                                .size(0)
                                .aggregations("brand_agg", a -> a.terms(t -> t.field("brand").size(2).order(new NamedValue<>("_count", SortOrder.Desc)))),
                HotelDoc.class);
        System.err.println(response);
        handleResponse(response);
    }

    /**
     * 嵌套Metrics 聚合函数
     * @param response
     */
    @Test
    void testAggMetrics() throws IOException {
        SearchResponse<HotelDoc> response = client.search(builder ->
                        builder.index("hotel")
                                .size(0)
                                .aggregations("brand_agg", a -> a.terms(t -> t.field("brand").size(2).order(new NamedValue<>("_count", SortOrder.Desc)))
                                        .aggregations("price_agg", b -> b.avg(c -> c.field("price")))),
               HotelDoc.class);
        System.err.println(response);
        //
//        response.aggregations().forEach((k, v) -> {
//            System.err.println(k);
//            System.err.println(v.get("price_agg"));
//        });
    }

    /**
     * 自动补全
     * @param response
     */
    @Test
    void testSuggest() throws IOException {
        SearchResponse<Map> response = client.search(builder ->
                        builder.index("hotel")
                                .suggest(s -> s.suggesters("suggestions",
                                        suggest -> suggest.prefix("hz").completion(c -> c.field("suggestion").skipDuplicates(true).size(10)))),
                Map.class);
        // 获取联想建议
        Map suggestMap = response.suggest();
        if (suggestMap != null) {
            List<?> suggestionList = (List<?>) suggestMap.get("suggestions");
            if (suggestionList != null) {
                for (Object suggestionInfo : suggestionList) {
                    if (suggestionInfo instanceof Suggestion) {
                        Suggestion suggestion = (Suggestion) suggestionInfo;
                        if (suggestion.isCompletion()) {
                            CompletionSuggest completionSuggest = suggestion.completion();
                            List<CompletionSuggestOption> options = completionSuggest.options();
                            for (CompletionSuggestOption option : options) {
                                System.err.println(option.text());
                            }
                        }
                    }
                }
            }
        }
    }


    private static void handleResponse(SearchResponse<HotelDoc> response) {
        System.err.println(response.hits().total().value());
        for (Hit<HotelDoc> doc : response.hits().hits()) {
            HotelDoc hotelDoc = doc.source();
            //System.err.println(doc);
            //System.err.println(doc.highlight());
            List<FieldValue> sortList = doc.sort();
            if(ObjectUtils.isNotEmpty(sortList)){
                hotelDoc.setDistance(sortList.get(0).doubleValue());
            }
            System.err.println(JSONObject.toJSONString(hotelDoc));
        }
    }

    @BeforeEach
    void setup() {
        BasicCredentialsProvider credsProv = new BasicCredentialsProvider();
        credsProv.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("elastic", "elastic"));

        restClient = RestClient.builder(HttpHost.create("http://127.0.0.1:9200"))
                .setHttpClientConfigCallback(hc -> hc.setDefaultCredentialsProvider(credsProv))
                .build();
        transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
        client = new ElasticsearchClient(transport);
    }

    @AfterEach
    void tearDown() throws Exception{
        client.shutdown();
        transport.close();
        restClient.close();
    }
}

项目下载地址

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Grain322

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值