一:准备工作

1.1配置文件

server:
  port: ${port:40100}
spring:
  application:
    name: xc-search-service
xuecheng:
  elasticsearch:
    hostlist: ${eshostlist:127.0.0.1:9200} #多个结点中间用逗号分隔

1.2配置类

@Configuration
public class ElasticsearchConfig {

    @Value("${xuecheng.elasticsearch.hostlist}")
    private String hostlist;

    @Bean
    public RestHighLevelClient restHighLevelClient(){
        //解析hostlist配置信息
        String[] split = hostlist.split(",");
        //创建HttpHost数组,其中存放es主机和端口的配置信息
        HttpHost[] httpHostArray = new HttpHost[split.length];
        for(int i=0;i

二:索引库的操作

测试类中要注入上一步定义好的bean

2.1新建索引库

@Test
public void testCreateIndex() throws IOException {
    //创建索引对象
    CreateIndexRequest createIndexRequest=new CreateIndexRequest("xc_course");
    //设置参数
    createIndexRequest.settings(Settings.builder().put("number_of_shards","1").put("number_of_replicas","0"));
    //指定映射
    createIndexRequest.mapping("doc","n" +
            "\"properties\": {\n" +
            "\"name\": {\n" +
            "\"type\": \"text\",\n" +
            "\"analyzer\":\"ik_max_word\",\n" +
            "\"search_analyzer\":\"ik_smart\"\n" +
            "},\n" +
            "\"description\": {\n" +
            "\"type\": \"text\",\n" +
            "\"analyzer\":\"ik_max_word\",\n" +
            "\"search_analyzer\":\"ik_smart\"\n" +
            "},\n" +
            "\"pic\":{\n" +
            "\"type\":\"text\",\n" +
            "\"index\":false\n" +
            "},\n" +
            "\"studymodel\":{\n" +
            "\"type\":\"text\"\n" +
            "}\n" +
            "}\n" +
            "}", XContentType.JSON);
    //操作索引的客户端
    IndicesClient indices = restHighLevelClient.indices();
    //执行添加所以有
    CreateIndexResponse response = indices.create(createIndexRequest);
    //得到响应
    boolean acknowledged = response.isAcknowledged();
    System.out.println(acknowledged);
}

2.2删除索引库

@Test
public void testDeleteIndex() throws IOException {
    //创建索引对象
    DeleteIndexRequest deleteIndexRequest=new DeleteIndexRequest("xc_course");
    //操作索引的客户端
    IndicesClient indices = restHighLevelClient.indices();
    //执行删除
    DeleteIndexResponse delete = indices.delete(deleteIndexRequest);
    //返回结果
    boolean acknowledged = delete.isAcknowledged();
    System.out.println(acknowledged);
}

三:文档的操作

3.1添加文档

@Test
public void testAddDoc() throws IOException {
    //准备json数据
    Map jsonMap = new HashMap<>();
    jsonMap.put("name", "spring cloud实战");
    jsonMap.put("description", "本课程主要从四个章节进行讲解: 1.微服务架构入门 2.spring cloud 基础入门 3.实战Spring Boot 4.注册中心eureka。");
    jsonMap.put("studymodel", "201001");
    SimpleDateFormat dateFormat =new SimpleDateFormat("yyyy‐MM‐dd HH:mm:ss");
    jsonMap.put("timestamp", dateFormat.format(new Date()));
    jsonMap.put("price", 5.6f);
    //索引请求对象
    IndexRequest indexRequest = new IndexRequest("xc_course","doc");
    //指定索引文档内容
    indexRequest.source(jsonMap);
    //索引响应对象
    IndexResponse indexResponse = restHighLevelClient.index(indexRequest);
    //获取响应内容
    DocWriteResponse.Result result = indexResponse.getResult();
    System.out.println(result);
}

3.2查询文档

@Test
public void testGetDoc() throws IOException {
    //查询请求对象
    GetRequest getRequest=new GetRequest("xc_course","doc","lJpazGsBtkIcW-SjsCSK");
    GetResponse getResponse = restHighLevelClient.get(getRequest);
    //得到文档的内容
    Map map = getResponse.getSourceAsMap();
    System.out.println(map);
}

3.3更新文档

@Test
public void testUpdateDoc() throws IOException {
    //更新请求对象
    UpdateRequest updateRequest=new UpdateRequest("xc_course","doc","lJpazGsBtkIcW-SjsCSK");
    //准备需要更新的数据
    Map jsonMap=new HashMap<>();
    jsonMap.put("name","林师妹");
    //指定doc
    updateRequest.doc(jsonMap);
    //执行更新
    UpdateResponse updateResponse = restHighLevelClient.update(updateRequest);
    //获取响应
    RestStatus status = updateResponse.status();
    System.out.println(status);
}

3.4删除文档

@Test
public void testDeleteDoc() throws IOException {
    //删除请求对象
    DeleteRequest deleteRequest=new DeleteRequest("xc_course","doc","lJpazGsBtkIcW-SjsCSK");
    //执行删除
    DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest);
    //获取响应结果
    DocWriteResponse.Result result = deleteResponse.getResult();
    System.out.println(result);
}

四:搜索管理

4.1搜索全部

@Test
public void testSearchAll() throws IOException{
    //搜索请求对象
    SearchRequest searchRequest=new SearchRequest("xc_course");
    //设置搜索类型
    searchRequest.types("doc");
    //搜索源构建对象
    SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder();
    //搜索方式 -- 搜索全部
    searchSourceBuilder.query(QueryBuilders.matchAllQuery());
    //设置过滤的字段 第一部分为需要的字段 第二部分为不需要的字段
    searchSourceBuilder.fetchSource(new String[]{"name","studymodel","price","description","timestamp"},new String[]{});
    //搜索对象中设置搜索源
    searchRequest.source(searchSourceBuilder);
    //客户端发送http请求
    SearchResponse searchResponse = restHighLevelClient.search(searchRequest);
    //获取查询结果
    SearchHits hits = searchResponse.getHits();
    SearchHit[] searchHits = hits.getHits();
    for (SearchHit hit:searchHits){
        Map sourceAsMap = hit.getSourceAsMap();
        String name = (String) sourceAsMap.get("name");
        Double price= (Double) sourceAsMap.get("price");
        String description = (String) sourceAsMap.get("description");
        String time = (String) sourceAsMap.get("timestamp");
        System.out.println(name+"\n"+price+"\n"+description+"\n"+time+"\n");
    }

4.2分页搜索

  • 在4.1的代码中添加如下代码即可
//设置分页参数
//页码
int page=1;
//每页记录数
int size=2;
//计算每页起始下标
int from=(page-1)*size;
searchSourceBuilder.from(from);
searchSourceBuilder.size(size);

4.3TermQuery

  • 注意

termQuery为精确查询,在搜索时会整体匹配关键字,不再将关键字分词。

  • 将4.1中搜索方式代码修改成如下即可
 //设置搜索方式 TermQuery
 searchSourceBuilder.query(QueryBuilders.termQuery("name","spring"));

4.4根据id精确查询

  • 注意

使用id查询时 代码应为termsQuery 4.3则为termQuery

  • 将4.1中搜索方式代码修改成如下即可
//主键
String[] ids=new String[]{"1","2"};
//设置搜索方式 TermsQuery
searchSourceBuilder.query(QueryBuilders.termsQuery("_id",ids));

4.5MatchQuery

match Query即全文检索,它的搜索方式是先将搜索字符串分词,再使用各各词条从索引中搜索。 match query与Term query区别是match query在搜索前先将搜索关键字分词,再拿各各词语去索引中搜索。

  • minimumShouldMatch
//设置搜索方式 matchQuery    3个关键字 3*0.7=2.1 取整搜索出现两个的记录 
searchSourceBuilder.query(QueryBuilders.matchQuery("description","spring开发框架").minimumShouldMatch("70%"));
  • operator
//设置搜索方式 matchQuery  or表示有其中一个就可以 and表示全部关键字都需要 
searchSourceBuilder.query(QueryBuilders.matchQuery("description","spring开发框架").operator(Operator.OR));

4.6MultiMatchQuery

上边学习的TermQuery和MatchQuery一次只能匹配一个Field

单项匹配是在一个field中去匹配,多项匹配是拿关键字去多个Field中匹配

  • 使用此方法 关键字中间必须需要空格 10是boost分数 表示×10倍
  • 此方法在实际开发中使用较多
//设置搜索方式 multiMatchQuery
searchSourceBuilder.query(QueryBuilders.multiMatchQuery("spring css","name","description")
                .minimumShouldMatch("50%").field("name",10));

4.7布尔查询

布尔查询对应于Lucene的BooleanQuery查询,实现将多个查询组合起来。

  • must:文档必须匹配must所包括的查询条件,相当于 “AND”
  • should:文档应该匹配should所包括的查询条件其 中的一个或多个,相当于 "OR"
  • must_not:文档不能匹配must_not所包括的该查询条件,相当于“NOT”
//设置搜索方式 multiMatchQuery
MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("spring css", "name", "description")
        .minimumShouldMatch("50%").field("name", 10);
//设置搜索方式 matchQuery
MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("studymodel", "201001");
//定义BoolQuery
BoolQueryBuilder boolQueryBuilder=new BoolQueryBuilder();
boolQueryBuilder.must(multiMatchQueryBuilder);
boolQueryBuilder.must(matchQueryBuilder);
searchSourceBuilder.query(boolQueryBuilder);

4.8过滤器

过滤是针对搜索的结果进行过滤,过滤器主要判断的是文档是否匹配,不去计算和判断文档的匹配度得分,所以过滤器性能比查询要高,且方便缓存,推荐尽量使用过滤器去实现查询或者过滤器和查询共同使用。过滤器在布尔查询中使用,下边是在搜索结果的基础上进行过滤:

  • 过滤出studymodel 为201001
  • 过滤出price区间为60-100
//设置搜索方式 multiMatchQuery
MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("spring css", "name", "description")
        .minimumShouldMatch("50%").field("name", 10);
//定义BoolQuery
BoolQueryBuilder boolQueryBuilder=new BoolQueryBuilder();
boolQueryBuilder.must(multiMatchQueryBuilder);
//定义过滤器
boolQueryBuilder.filter(QueryBuilders.termQuery("studymodel","201001"));
boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(60).lte(100));
searchSourceBuilder.query(boolQueryBuilder);

4.9排序

可以在字段上添加一个或多个排序,支持在keyword、date、float等类型上添加,text类型的字段上不允许添加排序。

//定义BoolQuery
BoolQueryBuilder boolQueryBuilder=new BoolQueryBuilder();
//定义过滤器
boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(0).lte(100));
searchSourceBuilder.query(boolQueryBuilder);
//设置排序 按照降序
searchSourceBuilder.sort("studymodel", SortOrder.DESC);

4.10高亮显示

高亮显示可以将搜索结果一个或多个字突出显示,以便向用户展示匹配关键字的位置。

  • 搜索方式
//设置搜索方式 multiMatchQuery
MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("spring css", "name", "description")
        .minimumShouldMatch("50%").field("name", 10);
//定义BoolQuery
BoolQueryBuilder boolQueryBuilder=new BoolQueryBuilder();
boolQueryBuilder.must(multiMatchQueryBuilder);
//定义过滤器
boolQueryBuilder.filter(QueryBuilders.termQuery("studymodel","201001"));
boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(0).lte(100));
searchSourceBuilder.query(boolQueryBuilder);
  • 高亮的设置
//设置高亮
HighlightBuilder highlightBuilder=new HighlightBuilder();
//设置前缀
highlightBuilder.preTags("");
//设置后缀
highlightBuilder.postTags("");
//设置高亮字段
highlightBuilder.fields().add(new HighlightBuilder.Field("name"));
searchSourceBuilder.highlighter(highlightBuilder);
  • 取值
String name = (String) sourceAsMap.get("name");
//取出name高亮
Map highlightFields = hit.getHighlightFields();
if (highlightFields!=null){
    HighlightField highlightField = highlightFields.get("name");
    if (highlightField!=null){
        Text[] fragments = highlightField.getFragments();
        StringBuffer stringBuffer=new StringBuffer();
        for (Text text:fragments){
            stringBuffer.append(text);
        }
        name=stringBuffer.toString();
    }
}

For sharing , For emulating , For enterprising