ElasticSearch:从创建数据到查询推荐API

前言 : 最近在看es,但是发现很少有从数据结构创建到应用的实例文章,所以决定自己写一个,共勉。

一 . 创建数据:

数据结构参考一下网站并稍加改动。

Elasticsearch 入门教程 - completion suggest实现搜索提示www.dczou.com图标

1.因为测试数据中存在中文,所以第一步需要导入中文分词器 (ik分词器),在bin目录下执行以下命令,执行完成后重启es。

bin/elasticsearch-plugin install github.com/medcl/elasti

2 . 创建index(news_website),index的json结构格式如下。

{ "mappings": {
"news" : {
"properties" : {
"title" : {
"type": "text",
"analyzer": "ik_max_word",
"fields": {
"suggest" : {
"type" : "completion",
"analyzer": "ik_max_word"
}
}
},
"content": {
"type": "text",
"analyzer": "ik_max_word"
},
"core":{
"type":"double"
},
"group":{
"type":"text"
}
}
}
}
}
索引名称: news_website
索引Type: news
字段:title 标题,ik 细粒度分词,支持suggest推荐查询。
字段:content 详情
字段:core 详情
字段:group 分组

3.加入maven依赖


    org.elasticsearch.client
    elasticsearch-rest-high-level-client
    6.5.3




    org.apache.logging.log4j
    log4j-api
    2.7




    org.apache.logging.log4j
    log4j-core
    2.7

4 . 创建客户端

public class InitClient {

    public static RestHighLevelClient getClient() {

        RestHighLevelClient client = new RestHighLevelClient(

                RestClient.builder(new HttpHost("localhost", 9200))
        );

        return client;
    }

}

5.创建索引的API

        try (RestHighLevelClient client = InitClient.getClient();) {
            // 创建索引名
            CreateIndexRequest request = new CreateIndexRequest("news_website");
            String source = "{\n" +
                    "      \"properties\" : {\n" +
                    "        \"title\" : {\n" +
                    "          \"type\": \"text\",\n" +
                    "          \"analyzer\": \"ik_max_word\",\n" +
                    "          \"fields\": {\n" +
                    "            \"suggest\" : {\n" +
                    "              \"type\" : \"completion\",\n" +
                    "              \"analyzer\": \"ik_max_word\"\n" +
                    "            }\n" +
                    "          }\n" +
                    "        },\n" +
                    "        \"content\": {\n" +
                    "          \"type\": \"text\",\n" +
                    "          \"analyzer\": \"ik_max_word\"\n" +
                    "        },\n" +
                    "\t\"core\":{\n" +
                    "\t\"type\":\"double\"\n" +
                    "\t},\n" +
                    "\t\"group\":{\n" +
                    "\t\"type\":\"text\"\n" +
                    "\t}\n" +
                    "      }\n" +
                    "    }";

            request.mapping("news", source, XContentType.JSON);
            CreateIndexResponse createIndexResponse = client.indices().create(request);
            //处理响应
            boolean acknowledged = createIndexResponse.isAcknowledged();
            boolean shardsAcknowledged = createIndexResponse.isShardsAcknowledged();
            System.out.println("acknowledged :" + acknowledged + "|  shardsAcknowledged: " + shardsAcknowledged);

        } catch (IOException e) {
            System.out.println(e);
        }

6.向索引中加入数据

        try (RestHighLevelClient client = InitClient.getClient();) {
            // 批量插入数据
            BulkRequest bulkRequest = new BulkRequest();
            // 获取数据
            String[] datas = getData();
            // 循环添加任务
            for (int i = ; i < datas.length; i++) {
                bulkRequest.add(
                        new IndexRequest("news_website", "news", i + 1 + "").
                                source(datas[i], XContentType.JSON)
                );
            }
            BulkResponse response = null;
            try {
                //提交请求
                response = client.bulk(bulkRequest, RequestOptions.DEFAULT);
            } catch (ElasticsearchException e) {
                logger.error(e);
            }
            // 返回请求状态
            if (response != null) {
                response.forEach(b -> {
                    DocWriteRequest.OpType opType = b.getOpType();
                    if (opType == DocWriteRequest.OpType.INDEX || opType == DocWriteRequest.OpType.CREATE) {
                        logger.info("创建数据成功!!!");
                    } else if (opType == DocWriteRequest.OpType.UPDATE) {
                        logger.info("更新数据成功!!!");
                    } else if (opType == DocWriteRequest.OpType.DELETE) {
                        logger.info("深处数据成功!!!");
                    }
                });
            }
        } catch (IOException e) {

            System.out.println(e);

        }
    // 创建数据
    private static String[] getData() {
        String[] strings = new String[5];

        strings[] = "{\n" +
                "\n" +
                "  \"title\": \"大话西游电影\",\n" +
                "\n" +
                "  \"content\": \"大话西游的电影时隔20年即将在2017年4月重映\",\n" +
                "\n" +
                "  \"core\" : 9.6,\n" +
                "\n" +
                "  \"group\" : \"电影\"\n" +
                "\n" +
                "}";
        strings[1] = "{\n" +
                "\n" +
                "  \"title\": \"大话西游小说\",\n" +
                "\n" +
                "  \"content\": \"某知名网络小说作家已经完成了大话西游同名小说的出版\",\n" +
                "\n" +
                "  \"core\" : 8.7,\n" +
                "\n" +
                "  \"group\" : \"小说\"\n" +
                "\n" +
                "}";
        strings[2] = "{\n" +
                "\n" +
                "  \"title\": \"大话西游手游\",\n" +
                "\n" +
                "  \"content\": \"网易游戏近日出品了大话西游经典IP的手游,正在火爆内测中\",\n" +
                "\n" +
                "  \"core\" : 7.8,\n" +
                "\n" +
                "  \"group\" : \"游戏\"\n" +
                "\n" +
                "}";
        strings[3] = "{\n" +
                "\n" +
                "  \"title\": \"cxk唱跳rap\",\n" +
                "\n" +
                "  \"content\": \"鸡你太美,鸡你实在实在太美!!!\",\n" +
                "\n" +
                "  \"core\" : 7.8,\n" +
                "\n" +
                "  \"group\" : \"游戏\"\n" +
                "\n" +
                "}";
        strings[4] = "{\n" +
                "\n" +
                "  \"title\": \"大话西游手游\",\n" +
                "\n" +
                "  \"content\": \"大话西游手游2也出来了你期待不\",\n" +
                "\n" +
                "  \"core\" : 7.8,\n" +
                "\n" +
                "  \"group\" : \"游戏\"\n" +
                "\n" +
                "}";
        return strings;
    }

7.遍历一下数据

        try (RestHighLevelClient client = InitClient.getClient();) {
            SearchRequest searchRequest = new SearchRequest("news_website");
            searchRequest.types("news");
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchRequest.source(searchSourceBuilder);
            SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
            // 处理返回值
            SearchHits hits = search.getHits();
            hits.forEach(hit -> {
                String sourceAsString = hit.getSourceAsString();
                System.out.println(sourceAsString);
                System.out.println("---------------------------------");
            });


        } catch (IOException e) {

            System.out.println(e);
        }
遍历结果

二 . 高亮查询,我们要在查询中高亮显示客户查询关键字(小说)

 try (RestHighLevelClient client = InitClient.getClient();) {
            // 指定索引
            SearchRequest request = new SearchRequest("news_website");
            // 指定类型
            request.types("news");
            // 构建
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            //构建查询体
            MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("title", "小说");
            searchSourceBuilder.query(matchQueryBuilder);
            // 构建高亮设置
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            //如果置为true,除非该字段的查询结果不为空才会被高亮
            highlightBuilder.requireFieldMatch(false);
            /*
               单字段单样式展示
               highlightBuilder.field("content").preTags("").postTags("");
             */
            // 多字段不同样式高亮展示
            HighlightBuilder.Field content = new HighlightBuilder.Field("content").preTags("").postTags("");
            HighlightBuilder.Field title = new HighlightBuilder.Field("title").preTags("").postTags("");
            highlightBuilder.field(content);
            highlightBuilder.field(title);

            searchSourceBuilder.highlighter(highlightBuilder);
            request.source(searchSourceBuilder);

            SearchResponse search = client.search(request, RequestOptions.DEFAULT);

            SearchHits hits = search.getHits();

            hits.forEach(hit -> {
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                System.out.println(hit.getSourceAsString());
                HighlightField highlight = highlightFields.get("content");
                if (highlight != null) {
                    Text[] fragments = highlight.fragments();
                    if (fragments != null) {
                        for (int i = ; i < fragments.length; i++) {
                            System.out.println("content highlight :" + fragments[i]);
                        }
                    }
                }

                HighlightField highlight_title = highlightFields.get("title");
                if (highlight != null) {
                    Text[] fragments = highlight_title.fragments();
                    if (fragments != null) {
                        for (int i = ; i < fragments.length; i++) {
                            System.out.println("title highlight :" + fragments[i]);
                        }
                    }
                }
                System.out.println("----------------------");
            });
        } catch (IOException e) {
            System.out.println(e);
        }

第一行是查询到的数据,第二行是在介绍中出现的小说字样并用 标签标记,第三行是表标题中 出现的‘小说’字段,并打标签。

三,纠错查询,在查询中客户可能输入错误关键字,根据数据库中的数据给予适当修整

        try (RestHighLevelClient client = InitClient.getClient()) {

            SearchRequest request = new SearchRequest("news_website");

            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            SuggestBuilder suggestBuilder = new SuggestBuilder();

            TermSuggestionBuilder termSuggestionBuilder =
                    SuggestBuilders.termSuggestion("title.suggest").text("cxk长跳rwp");
            suggestBuilder.addSuggestion("title_suggest", termSuggestionBuilder);
            searchSourceBuilder.suggest(suggestBuilder);
            request.source(searchSourceBuilder);
            SearchResponse search = client.search(request, RequestOptions.DEFAULT);
            if (search.status().equals(RestStatus.OK)) {
                Suggest suggest = search.getSuggest();
                //获取建议结果
                TermSuggestion title_suggest = suggest.getSuggestion("title_suggest");
                title_suggest.getEntries().forEach(s -> {
                    System.out.println("您输入的是 : " + s.getText());
                    s.forEach(o -> {
                        System.out.println("你是不是要找 : " + o.getText());
                    });
                });
            }
        } catch (IOException e) {
            System.out.println(e);
 }

四.查询补全,根据用户输入的头几个字猜后边想要输入的内容

        try (RestHighLevelClient client = InitClient.getClient()) {
            SearchRequest searchRequest = new SearchRequest("news_website");

            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            
            CompletionSuggestionBuilder suggestionBuilder = SuggestBuilders.completionSuggestion("title.suggest").prefix("大话西游");
//            suggestionBuilder
            SuggestBuilder suggestBuilder = new SuggestBuilder();
            //起个别名
            suggestBuilder.addSuggestion("title_suggest", suggestionBuilder);
            // 装进source里
            searchSourceBuilder.suggest(suggestBuilder);
            searchRequest.source(searchSourceBuilder);
            SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
            if (RestStatus.OK.equals(search.status())) {
                Suggest suggest = search.getSuggest();
                CompletionSuggestion termSuggestion = suggest.getSuggestion("title_suggest");
                termSuggestion.forEach(entity -> {
                    System.out.println("  text: " + entity.getText().toString());
                    entity.forEach(o -> {
                        System.out.println("suggest : " + o.getText().toString());
                    });
                });
            }
        } catch (IOException e) {
            System.out.println(e);
        }
    }

输入了‘大话西游’,会将数据中其他相关内容推荐出来。

请使用浏览器的分享功能分享到微信等