【ES三周年】吊打Elasticsearch 和Java API(进阶保姆级教程-3)(es周年庆)
 南窗  分类:IT技术  人气:171  回帖:0  发布于1年前 收藏

前言

上一篇我们通过kibana的可视化界面,对es的索引以及文档的常用操作做了毕竟详细的总结,本篇将介绍如何使用java完成对es的操作,这也是实际开发中将要涉及到的。

1.Java API 操作

随着 Elasticsearch 8.x 新版本的到来,Type 的概念被废除,为了适应这种数据结构的改 变,Elasticsearch 官方从 7.15 版本开始建议使用新的 Elasticsearch Java Client。

2.java操作es的常用模式

目前,开发中使用java操作es,不管是框架集成,还是纯粹的使用es的api,主要通过下面两种方式:

rest-api,主流的像 RestHighLevelClient ;

与springboot集成时的jpa操作,主要是 ElasticsearchRepository 相关的api;

上面两种模式的api在开发中都可以方便的使用,相比之下,RestHighLevelClient相关的api灵活性更高,而ElasticsearchRepository 底层做了较多的封装,学习和使用的成本更低,上手更快。

接下来将对上面的两种操作模式做一个详细的总结,本篇所述的es基于7.6.1版本,配合的kibana也为7.6.1版本。

3.rest-api 操作

3.1准备工作

3.1.1导入依赖

导入核心依赖,主要是es的rest依赖,其他的可以根据自己的需要导入;宏哥这里就直接将自己的pom.xml文件内容粘贴过来了。

<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>

  <groupId>ElasticSearch</groupId>
  <artifactId>ElasticSearch</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>ElasticSearch</name>
  <url>https://mvnrepository.com/artifact/org.elasticsearch/elasticsearch</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.elasticsearch/elasticsearch -->
    <dependency>
        <groupId>org.elasticsearch</groupId>
        <artifactId>elasticsearch</artifactId>
        <version>7.6.1</version>
    </dependency>
    
     <!--  elasticsearch 的客户端 -->
     <dependency>
     <groupId>org.elasticsearch.client</groupId>
     <artifactId>elasticsearch-rest-high-level-client</artifactId>
     <version>7.6.1</version>
     </dependency>
     <!-- elasticsearch 依赖 2.x 的 log4j -->
     <dependency>
     <groupId>org.apache.logging.log4j</groupId>
     <artifactId>log4j-api</artifactId>
     <version>2.8.2</version>
     </dependency>
     <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.1</version>
     </dependency>
  </dependencies>
</project>

3.1.2ES连接测试

新建一个EsClientTest测试类,输入如下代码:

package ElasticSearch.ElasticSearch;

import org.apache.http.HttpHost;
import java.io.IOException;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;

import com.fasterxml.jackson.databind.ObjectMapper;

public class EsClientTest {
	
	
	//测试连接ES
//	public static void main(String[] args) throws IOException {
//        RestHighLevelClient esClient = new RestHighLevelClient(
//                RestClient.builder(new HttpHost("IP",9200,"http"))
//        );
//        System.out.println("success");
//        esClient.close();
//    }
	//为了减少连接相关的编码,我们将es的client提出到全局的静态变量中,其他方法中就可以直接引用了
	public static ObjectMapper objectMapper = new ObjectMapper();

	public static RestHighLevelClient esClient;

	static {

		esClient = new RestHighLevelClient(RestClient.builder(new HttpHost("127.0.0.1", 9200, "http")));
	}
}

3.1.3运行代码测试连接

运行上面的代码,出现下面的效果说明连接成功

4.索引相关操作api的使用

为了减少连接相关的编码,我们将es的client提出到全局的静态变量中,其他方法中就可以直接引用了

public static RestHighLevelClient esClient;

    static {
    
        esClient = new RestHighLevelClient(RestClient.builder(new HttpHost("IP", 9200, "http")));
    }

注意:要将IP替换成你安装ES电脑或者服务器的IP。

4.1创建索引

1.新建一个CreateIndex类,输入如下代码:

package ElasticSearch.ElasticSearch;

import java.io.IOException;

import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.client.RequestOptions;
import org.junit.Test;

public class CreateIndex {

    /**
     * 创建索引
     * 
     * @throws IOException
     */
    @Test
    public void createIndex() throws IOException {
        CreateIndexRequest createIndexRequest = new CreateIndexRequest("user");
        CreateIndexResponse indexResponse = EsClientTest.esClient.indices().create(createIndexRequest,RequestOptions.DEFAULT);
        boolean acknowledged = indexResponse.isAcknowledged();
        System.out.println("索引创建状态:" + acknowledged);
    }

}

2.运行代码

3.通过ES客户端界面查询确认索引是否创建成功

4.2获取索引(查询索引)

1.新建一个GetIndex类,输入如下代码:

package ElasticSearch.ElasticSearch;

import java.io.IOException;

import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.GetIndexResponse;
import org.junit.Test;

public class GetIndex {

    /**
     * 索引信息查询
     * 
     * @throws IOException
     */
    @Test
    public void getIndex() throws IOException {
        GetIndexRequest getIndexRequest = new GetIndexRequest("user");
        GetIndexResponse getIndexResponse = EsClientTest.esClient.indices().get(getIndexRequest,RequestOptions.DEFAULT);
        System.out.println(getIndexResponse.getAliases());
        System.out.println(getIndexResponse.getMappings());
        System.out.println(getIndexResponse.getSettings());
    }

}

2.运行代码

4.3删除索引

1.新建一个DeleteIndex类,输入如下代码:

package ElasticSearch.ElasticSearch;

import java.io.IOException;

import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.junit.Test;

public class DeleteIndex {

    /**
     * 删除索引
     * 
     * @throws IOException
     */
    @Test
    public void deleteIndex() throws IOException {
        DeleteIndexRequest getIndexRequest = new DeleteIndexRequest("user");
        AcknowledgedResponse delete = EsClientTest.esClient.indices().delete(getIndexRequest, RequestOptions.DEFAULT);
        System.out.println("索引删除状态:" + delete.isAcknowledged());
    }

}

2.运行代码

3.通过ES客户端界面查询确认索引是否删除成功

5.文档常用操作api的使用

在实际开发过程中,对于文档的操作更为的频繁,接下来演示与ES文档相关的操作api。

5.1准备工作

1.在EsClientTest类中加入如下代码备用:

public static ObjectMapper objectMapper = new ObjectMapper();

2.用于测试的对象,新建一个User类:

package ElasticSearch.ElasticSearch;

public class User {

    private String name;
    private String sex;
    private Integer age;

    private Integer salary;

    public User() {
    }

    public User(String name, String sex, Integer age, Integer salary) {
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.salary = salary;
    }

    public Integer getSalary() {
        return salary;
    }

    public void setSalary(Integer salary) {
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

}

5.2索引添加文档

1.新建一个AddDoc类,输入如下代码:

package ElasticSearch.ElasticSearch;

import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.Test;

public class AddDoc {

    /**
     * 添加数据
     * 
     * @throws Exception
     */
    @Test
    public void add() throws Exception {
        IndexRequest indexRequest = new IndexRequest();
        indexRequest.index("user").id("1008");
        User user = new User();
        user.setName("孙二娘");
        user.setAge(23);
        user.setSex("女");
        user.setSalary(7000);

        String userData = EsClientTest.objectMapper.writeValueAsString(user);
        indexRequest.source(userData, XContentType.JSON);
        // 插入数据
        IndexResponse response = EsClientTest.esClient.index(indexRequest, RequestOptions.DEFAULT);
        System.out.println(response.status());
        System.out.println(response.getResult());
        EsClientTest.esClient.close();
    }
}

2.运行代码

3.通过ES客户端界面查询确认数据是否添加成功

5.3修改文档

1.新建一个UpdateDoc类,输入如下代码:

package ElasticSearch.ElasticSearch;

import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.Test;

public class UpdateDoc {

    /**
     * 修改数据
     * 
     * @throws Exception
     */
    @Test
    public void update() throws Exception {
        UpdateRequest request = new UpdateRequest();
        request.index("user").id("1008");
        request.doc(XContentType.JSON, "name", "母夜叉");
        // 插入数据
        UpdateResponse response = EsClientTest.esClient.update(request, RequestOptions.DEFAULT);
        System.out.println(response.getResult());
    }

}

2.运行代码

3.通过ES客户端界面查询确认数据是否修改成功

5.4删除文档

1.新建一个DeleteDoc类,输入如下代码:

package ElasticSearch.ElasticSearch;

import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.client.RequestOptions;

package ElasticSearch.ElasticSearch;

import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.client.RequestOptions;
import org.junit.Test;

public class DeleteDoc {

	/**
	 * 删除
	 * 
	 * @throws Exception
	 */
	@Test
	public void delete() throws Exception {
		DeleteRequest request = new DeleteRequest();
		request.index("user").id("1008");
		// 插入数据
		DeleteResponse delete = EsClientTest.esClient.delete(request, RequestOptions.DEFAULT);
		System.out.println(delete.getResult());
	}

}

2.运行代码

3.通过ES客户端界面查询确认数据是否删除成功

5.5批量添加文档

1.新建一个BatchInsertDoc类,输入如下代码:

package ElasticSearch.ElasticSearch;

import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.Test;

public class BatchInsertDoc {

	/**
	 * 批量添加
	 * 
	 * @throws Exception
	 */
	@Test
	public void batchInsert() throws Exception {

		BulkRequest bulkRequest = new BulkRequest();

		User user1 = new User("关羽", "男", 33, 5500);
		String userData1 = EsClientTest.objectMapper.writeValueAsString(user1);
		IndexRequest indexRequest1 = new IndexRequest().index("user").id("1002").source(userData1, XContentType.JSON);

		bulkRequest.add(indexRequest1);

		User user2 = new User("黄忠", "男", 50, 8000);
		String userData2 = EsClientTest.objectMapper.writeValueAsString(user2);
		IndexRequest indexRequest2 = new IndexRequest().index("user").id("1003").source(userData2, XContentType.JSON);
		bulkRequest.add(indexRequest2);

		User user3 = new User("黄忠2", "男", 49, 10000);
		String userData3 = EsClientTest.objectMapper.writeValueAsString(user3);
		IndexRequest indexRequest3 = new IndexRequest().index("user").id("1004").source(userData3, XContentType.JSON);
		bulkRequest.add(indexRequest3);

		User user4 = new User("赵云", "男", 33, 12000);
		String userData4 = EsClientTest.objectMapper.writeValueAsString(user4);
		IndexRequest indexRequest4 = new IndexRequest().index("user").id("1005").source(userData4, XContentType.JSON);
		bulkRequest.add(indexRequest4);

		User user5 = new User("马超", "男", 38, 20000);
		String userData5 = EsClientTest.objectMapper.writeValueAsString(user5);
		IndexRequest indexRequest5 = new IndexRequest().index("user").id("1006").source(userData5, XContentType.JSON);
		bulkRequest.add(indexRequest5);

		User user6 = new User("关羽", "男", 41, 27000);
		String userData6 = EsClientTest.objectMapper.writeValueAsString(user6);
		IndexRequest indexRequest6 = new IndexRequest().index("user").id("1007").source(userData6, XContentType.JSON);
		bulkRequest.add(indexRequest6);

		BulkResponse bulkResponse = EsClientTest.esClient.bulk(bulkRequest, RequestOptions.DEFAULT);
		System.out.println(bulkResponse.status());
		System.out.println(bulkResponse.getItems());
	}

}

2.运行代码

3.通过ES客户端界面查询确认数据是否批量添加成功

5.6批量删除文档

1.新建一个BatchDeleteDoc类,输入如下代码:

package ElasticSearch.ElasticSearch;

import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.client.RequestOptions;
import org.junit.Test;

public class BatchDeleteDoc {

	/**
	 * 批量删除
	 * 
	 * @throws Exception
	 */
	@Test
	public void batchDelete() throws Exception {
		BulkRequest bulkRequest = new BulkRequest();
		DeleteRequest indexRequest1 = new DeleteRequest().index("user").id("1002");
		DeleteRequest indexRequest2 = new DeleteRequest().index("user").id("1003");
		DeleteRequest indexRequest3 = new DeleteRequest().index("user").id("1004");
		DeleteRequest indexRequest4 = new DeleteRequest().index("user").id("1005");
		DeleteRequest indexRequest5 = new DeleteRequest().index("user").id("1006");
		DeleteRequest indexRequest6 = new DeleteRequest().index("user").id("1007");

		bulkRequest.add(indexRequest1);
		bulkRequest.add(indexRequest2);
		bulkRequest.add(indexRequest3);
		bulkRequest.add(indexRequest4);
		bulkRequest.add(indexRequest5);
		bulkRequest.add(indexRequest6);

		BulkResponse bulkResponse = EsClientTest.esClient.bulk(bulkRequest, RequestOptions.DEFAULT);
		System.out.println(bulkResponse.status());
		System.out.println(bulkResponse.getItems());
	}

}

2.运行代码

3.通过ES客户端界面查询确认数据是否批量删除成功

6.文档搜索相关api的使用

我们知道es最强大的功能就是文档检索了,接下来演示下与es文档查询相关的常用API的操作。

6.1查询某个索引下的所有数据

1.新建一个SearchIndexAll类,输入如下代码:

package ElasticSearch.ElasticSearch;

import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.Test;

public class SearchIndexAll {

	/**
	 * 查询某个索引下的所有数据
	 * 
	 * @throws Exception
	 */
	@Test
	public void searchIndexAll() throws Exception {
		SearchRequest request = new SearchRequest();
		request.indices("user");
		// 索引中的全部数据查询
		SearchSourceBuilder query = new SearchSourceBuilder().query(QueryBuilders.matchAllQuery());
		request.source(query);
		SearchResponse response = EsClientTest.esClient.search(request, RequestOptions.DEFAULT);
		SearchHits hits = response.getHits();
		for (SearchHit searchHit : hits) {
			System.out.println(searchHit.getSourceAsString());
		}
	}

}

2.运行代码

3.通过ES客户端界面查询数据是一致的

6.2批量查询多条数据

针对那种需要一次性查出多条数据的场景可以考虑使用

1.新建一个MultiGetDoc类,输入如下代码:

package ElasticSearch.ElasticSearch;

import java.util.Iterator;

import org.elasticsearch.action.get.MultiGetItemResponse;
import org.elasticsearch.action.get.MultiGetRequest;
import org.elasticsearch.action.get.MultiGetResponse;
import org.elasticsearch.client.RequestOptions;
import org.junit.Test;

public class MultiGetDoc {
	
	
	 /**
	     * 批量查询多条数据
	 * 
	 * @throws Exception
	 */
	@Test
	public void searchIndexAll() throws Exception {
		MultiGetRequest multiGetRequest = new MultiGetRequest();
		multiGetRequest.add("user","1002");
		multiGetRequest.add("user","1003");
		MultiGetResponse responses = EsClientTest.esClient.mget(multiGetRequest, RequestOptions.DEFAULT);
		Iterator<MultiGetItemResponse> iterator = responses.iterator();while(iterator.hasNext())
		{
			MultiGetItemResponse next = iterator.next();
			System.out.println(next.getResponse().getSourceAsString());
		}
	}
}

2.运行代码

6.3根据条件精准查询

根据性别查询,有点类似于mysql 中的 where sex='女' 这样的效果

1.新建一个TermQueryDoc类,输入如下代码:

package ElasticSearch.ElasticSearch;

import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.Test;

public class TermQueryDoc {
	
	 //private static final SearchRequest request = null;

	/**
	     *根据条件精准查询
	 * 
	 * @throws Exception
	 */
	@Test
	public void termQueryDoc() throws Exception {
		SearchRequest request = new SearchRequest();
		TermQueryBuilder ageQueryBuilder = QueryBuilders.termQuery("sex", "女");
        SearchSourceBuilder query = new SearchSourceBuilder().query(ageQueryBuilder);
        request.source(query);
        SearchResponse response = EsClientTest.esClient.search(request, RequestOptions.DEFAULT);
        System.out.println(response.getHits().getHits());
        System.out.println(response.getHits().getTotalHits());
        SearchHits hits = response.getHits();
        for (SearchHit searchHit : hits){
            System.out.println(searchHit.getSourceAsString());
        }
	}

}

2.运行代码

6.4分页查询

考察from + size的使用。

1.新建一个Paging类,输入如下代码:

package ElasticSearch.ElasticSearch;

import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.Test;

public class Paging {
	
	
	/**
	     *分页查询
	 * 
	 * @throws Exception
	 */
	@Test
	public void paging() throws Exception {
		//分页查询数据
		SearchRequest request = new SearchRequest();
		request.indices("user");
		SearchSourceBuilder sourceBuilder = new SearchSourceBuilder().query(QueryBuilders.matchAllQuery());
		// (当前页码-1)*每页显示数据条数
        sourceBuilder.from(0);//起始页
        sourceBuilder.size(3);  // 每页有多少条
        request.source(sourceBuilder);
        SearchResponse response = EsClientTest.esClient.search(request, RequestOptions.DEFAULT);
        System.out.println(response.getHits().getHits());
        System.out.println(response.getHits().getTotalHits());
        SearchHits hits = response.getHits();
        for (SearchHit searchHit : hits){
            System.out.println(searchHit.getSourceAsString());
        }
        // 关闭ES客户端
        
        EsClientTest.esClient.close();
	}
}

2.运行代码

6.5查询结果按照某个字段排序

类似于mysql中只查询某个表的部分字段。

1.新建一个SearchIndexAll类,输入如下代码:

package ElasticSearch.ElasticSearch;

import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.Test;

public class QuerySortByAge {

	/**
	 * 排序查询
	 * 
	 * @throws Exception
	 */
	@Test
	public void querySortByAge() throws Exception {

		SearchRequest request = new SearchRequest();
		request.indices("user");
		SearchSourceBuilder sourceBuilder = new SearchSourceBuilder().query(QueryBuilders.matchAllQuery());
		sourceBuilder.sort("age", SortOrder.ASC);
		request.source(sourceBuilder);
		SearchResponse response = EsClientTest.esClient.search(request, RequestOptions.DEFAULT);
		System.out.println(response.getHits().getHits());
		System.out.println(response.getHits().getTotalHits());
		SearchHits hits = response.getHits();
		for (SearchHit searchHit : hits) {
			System.out.println(searchHit.getSourceAsString());
		}

	}

}

2.运行代码

6.6查询结果过滤某些字段

1.新建一个SearchIndexAll类,输入如下代码:

package ElasticSearch.ElasticSearch;

import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.Test;

public class QueryFilter {

	/**
	 * 过滤查询
	 * 
	 * @throws Exception
	 */
	@Test
	public void queryFilter() throws Exception {

		SearchRequest request = new SearchRequest();
		request.indices("user");
		SearchSourceBuilder sourceBuilder = new SearchSourceBuilder().query(QueryBuilders.matchAllQuery());
		request.source(sourceBuilder);
		String[] includes = { "name", "sex" };
		String[] excludes = { "age" };
		sourceBuilder.fetchSource(includes, excludes);
		SearchResponse response = EsClientTest.esClient.search(request, RequestOptions.DEFAULT);
		System.out.println(response.getHits().getHits());
		System.out.println(response.getHits().getTotalHits());
		SearchHits hits = response.getHits();
		for (SearchHit searchHit : hits) {
			System.out.println(searchHit.getSourceAsString());
		}

	}

}

2.运行代码

6.7多条件查询

es可以像mysql那样组合多个条件进行查询,考察对BoolQuery的使用,如下:查询性别为难男,年龄在35到45之间的用户。

1.新建一个MultiConditionQuery类,输入如下代码:

package ElasticSearch.ElasticSearch;

import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.Test;

public class MultiConditionQuery {
	
	/**
	   * 多条件查询
	 * 
	 * @throws Exception
	 */
	@Test
	public void multiConditionQuery() throws Exception {

		SearchRequest request = new SearchRequest();
		request.indices("user");
		SearchSourceBuilder sourceBuilder = new SearchSourceBuilder().query(QueryBuilders.matchAllQuery());
		BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.matchQuery("sex","男"));
        boolQueryBuilder.must(QueryBuilders.rangeQuery("age").lt(45).gt(35));
        sourceBuilder.query(boolQueryBuilder);
        request.source(sourceBuilder);
        SearchResponse response = EsClientTest.esClient.search(request, RequestOptions.DEFAULT);

        System.out.println(response.getHits().getHits());
        System.out.println(response.getHits().getTotalHits());
        SearchHits hits = response.getHits();
        for (SearchHit searchHit : hits){
            System.out.println(searchHit.getSourceAsString());
        }

	}

}

2.运行代码

6.8范围查询

1.新建一个RangeQuery类,输入如下代码:

package ElasticSearch.ElasticSearch;

import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.Test;

public class RangeQuery {

	/**
	 * 范围查询
	 * 
	 * @throws Exception
	 */
	@Test
	public void rangeQuery() throws Exception {

		SearchRequest request = new SearchRequest();
		request.indices("user");

		SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        RangeQueryBuilder rangeQueryBuilder =     
        QueryBuilders.rangeQuery("age").gte(35).lte(45);
        sourceBuilder.query(rangeQueryBuilder);
        request.source(sourceBuilder);
        SearchResponse response = EsClientTest.esClient.search(request, RequestOptions.DEFAULT);
        System.out.println(response.getHits().getHits());
        System.out.println(response.getHits().getTotalHits());
        SearchHits hits = response.getHits();
        for (SearchHit searchHit : hits){
            System.out.println(searchHit.getSourceAsString());
        }

	}

}

2.运行代码

6.9模糊查询

1.新建一个LikeQuery类,输入如下代码:

package ElasticSearch.ElasticSearch;

import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.index.query.FuzzyQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.Test;

public class LikeQuery {

	/**
	 * 模糊查询
	 * 
	 * @throws Exception
	 */
	@Test
	public void likeQuery() throws Exception {

		SearchRequest request = new SearchRequest();
		request.indices("user");

		SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
		FuzzyQueryBuilder fuzzyQueryBuilder = QueryBuilders.fuzzyQuery("name", "黄忠").fuzziness(Fuzziness.ONE);
		sourceBuilder.query(fuzzyQueryBuilder);
		request.source(sourceBuilder);
		SearchResponse response = EsClientTest.esClient.search(request, RequestOptions.DEFAULT);
		System.out.println(response.getHits().getHits());
		System.out.println(response.getHits().getTotalHits());
		SearchHits hits = response.getHits();
		for (SearchHit searchHit : hits) {
			System.out.println(searchHit.getSourceAsString());
		}

	}

}

2.运行代码

6.10高亮查询

6.10.1什么是高亮?

在进行关键字搜索时,搜索出的内容中的关键字会显示不同的颜色,称之为高亮。例如:百度搜索关键字"ElasticSearch"时会红色高亮显示

通过开发者工具查看高亮数据的html代码实现:

ElasticSearch可以对查询出的内容中关键字部分进行标签和样式的设置,但是你需要告诉ElasticSearch使用什么标签对高亮关键字进行包裹。具体操作步骤如下:

1.新建一个HighlightQuery类,输入如下代码:

package ElasticSearch.ElasticSearch;

import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.junit.Test;

public class HighlightQuery {

	/**
	 * 高亮查询
	 * 
	 * @throws Exception
	 */
	@Test
	public void highLightQuery() throws Exception {

		SearchRequest request = new SearchRequest();
		request.indices("user");
		SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
		TermQueryBuilder ageQueryBuilder = QueryBuilders.termQuery("age", 33);
		HighlightBuilder highlightBuilder = new HighlightBuilder();
		highlightBuilder.preTags("<font color='red'>");
		highlightBuilder.postTags("</font>");
		highlightBuilder.field("name");
		sourceBuilder.highlighter(highlightBuilder);
		sourceBuilder.query(ageQueryBuilder);
		request.source(sourceBuilder);
		SearchResponse response = EsClientTest.esClient.search(request, RequestOptions.DEFAULT);
		System.out.println(response.getHits().getHits());
		System.out.println(response.getHits().getTotalHits());
		SearchHits hits = response.getHits();
		for (SearchHit searchHit : hits) {
			System.out.println(searchHit.getSourceAsString());
		}
	}
}

2.运行代码

6.11多字段查询multi_match

1.新建一个MultiMatchQuery类,输入如下代码:

package ElasticSearch.ElasticSearch;

import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;

import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.Test;

public class MultiMatchQuery {

	/**
	 * 多字段查询匹配某个关键字
	 * 
	 * @throws Exception
	 */
	@Test
	public void multiMatchQuery() throws Exception {

		SearchRequest request = new SearchRequest();
		request.indices("user");
		SearchSourceBuilder builder = new SearchSourceBuilder();
        MultiMatchQueryBuilder multiMatchQuery = QueryBuilders.multiMatchQuery("黄忠","name", "sex");
        multiMatchQuery.operator(Operator.OR);
        builder.query(multiMatchQuery);
        request.source(builder);
        SearchResponse response = EsClientTest.esClient.search(request, RequestOptions.DEFAULT);
        System.out.println(response.getHits().getHits());
        System.out.println(response.getHits().getTotalHits());
        SearchHits hits = response.getHits();
        for (SearchHit searchHit : hits){
            System.out.println(searchHit.getSourceAsString());
        }
	}

}

2.运行代码

6.12聚合查询

1.新建一个AggregationQuery类,输入如下代码:

package ElasticSearch.ElasticSearch;

import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.Test;

public class AggregationQuery {

	/**
	 * 聚合查询
	 * 
	 * @throws Exception
	 */
	@Test
	public void multiMatchQuery() throws Exception {

		SearchRequest request = new SearchRequest();
		request.indices("user");
		SearchSourceBuilder builder = new SearchSourceBuilder();
		AggregationBuilder aggregationBuilder = AggregationBuilders.max("maxAge").field("age");
		builder.aggregation(aggregationBuilder);
		request.source(builder);
		SearchResponse response = EsClientTest.esClient.search(request, RequestOptions.DEFAULT);
		System.out.println(response.getHits().getHits());
		System.out.println(response.getHits().getTotalHits());
		SearchHits hits = response.getHits();
		for (SearchHit searchHit : hits) {
			System.out.println(searchHit.getSourceAsString());
		}
	}

}

2.运行代码

6.13分组查询

1.新建一个GroupQuery类,输入如下代码:

package ElasticSearch.ElasticSearch;

import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.Test;

public class GroupQuery {
	

	/**
	 * 分组查询
	 * 
	 * @throws Exception
	 */
	@Test
	public void groupQuery() throws Exception {

		SearchRequest request = new SearchRequest();
		request.indices("user");
		SearchSourceBuilder builder = new SearchSourceBuilder();
		AggregationBuilder aggregationBuilder = AggregationBuilders.terms("ageGroup").field("age");
        builder.aggregation(aggregationBuilder);
        request.source(builder);

        SearchResponse response = EsClientTest.esClient.search(request, RequestOptions.DEFAULT);
        System.out.println(response.getHits().getHits());
        System.out.println(response.getHits().getTotalHits());
        SearchHits hits = response.getHits();
        for (SearchHit searchHit : hits){
            System.out.println(searchHit.getSourceAsString());
        }
	}
}

2.运行代码

7.与Springboot整合

es提供了与spring,springboot快速整合的第三方SDK,接下来以spring-data为例进行说明;

spring-boot-starter-data-elasticsearch 与spring其他相关的jpa方式使用类似,封装了丰富的API接口,客户只需要继承其提供的接口,就能方便的使用内置的API

7.1使用Eclipse搭建SpringBoot项目

7.1.1创建项目过程

1.点击eclipse左上角File—New—Other

2.选择 Maven Project,点击Next

3.选择项目存放位置,点击Next

4.选择以 quickstart 或者webapp结尾的点击Next

5.填写好Group Id、 Artifact Id , 填写好后,Package一栏会自动生成,这也就是项目中的包名,点击Finish

6.项目创建完成

第一次创建springboot项目时,创建完成后项目会有一个红叉(虽然不影响运行)

原因: maven默认编译版本与使用的jdk不匹配

解决办法: 选中工程:右键单击–> Maven --> Update Project

什么都不用管,直接点击ok就行

解决完成,小红叉消失了

7.2加入相关依赖、配置

1.加入SpringBoot框架: 打开pom.xml文件

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.6.RELEASE</version>
        <relativePath/>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
        </dependency>
    </dependencies>

7.3常用配置设置

创建 resources文件夹 ,这个文件夹主要用来存放配置资源的,如果创建项目时已经存在则不需要再创建了,没有就手动创建一个。

这是宏哥刚创建的一个maven项目,由此可以看见,项目并没有存放配置文件的src/main/resources文件夹?

解决方案:

1.选中项目,右键单击,如图所示选择:Build Path --> Configure Build Path

2.选中src/main/java目录,然后点击Add Floder

3. 选中main,然后点击下方的Create new Floder

4.然后输入resources,点击Finish

5.这时候,上一个界面就有一个该resources文件夹了,然后点击OK。

6.这时返回到更上一级界面,这个时候可以看到.../src/main/resoures已经生成了,继续点击OK,该界面会自动关闭。

7.回到项目上,这个文件夹已经被创建好了!于是,问题已被解决!

7.3.1核心配置

1.在刚刚创建的 src/main/java/resources/文件夹 上右键—new—other创建application.properties

# es IP
elasticsearch.host=127.0.0.1
# es 端口
elasticsearch.port=9200
# 配置日志级别,开启debug日志
logging.level.com.congge=debug

7.3.2创建一个实体类

该实体类属于连接es文档与客户端的一个中间转换层,使用过jpa或者mybatis-plus的同学对这个应该不陌生。

package springframework.springframework.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Document(indexName = "shopping", shards = 3, replicas = 1)
public class Product{
    //必须有 id,这里的 id 是全局唯一的标识,等同于 es 中的"_id"
    @Id
    private Long id;//商品唯一标识

    /**
     * type : 字段数据类型
     * analyzer : 分词器类型
     * index : 是否索引(默认:true)
     * Keyword : 短语,不进行分词
     */
    @Field(type = FieldType.Text, analyzer = "ik_max_word")
    private String title;//商品名称

    @Field(type = FieldType.Keyword)
    private String category;//分类名称

    @Field(type = FieldType.Double)
    private Double price;//商品价格

    @Field(type = FieldType.Keyword, index = false)
    private String images;//图片地址

	public void setId(long l) {
		// TODO Auto-generated method stub
		
	}

	public void setTitle(String string) {
		// TODO Auto-generated method stub
		
	}

	public void setCategory(String string) {
		// TODO Auto-generated method stub
		
	}

	public void setPrice(double d) {
		// TODO Auto-generated method stub
		
	}

	public void setImages(String string) {
		// TODO Auto-generated method stub
		
	}
    
}

7.3.3创建一个接口

接口,继承ElasticsearchRepository

package springframework.springframework.dao;

import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
import springframework.springframework.entity.Product;

@Repository
public interface ProductDao extends ElasticsearchRepository<Product, Long>{

}

7.3.4ES核心配置类

package springframework.springframework.config;

import lombok.Data;
import springframework.springframework.AbstractElasticsearchConfiguration;

import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;


//@PropertySource(value = "application.properties")
@Configuration
@Data
@ConfigurationProperties(prefix = "elasticsearch")
public class EsConfig extends AbstractElasticsearchConfiguration {

    private String host ;
    private Integer port ;

    //重写父类方法
    @Override
    public RestHighLevelClient elasticsearchClient() {
        RestClientBuilder builder = RestClient.builder(new HttpHost(host, port));
        RestHighLevelClient restHighLevelClient = new RestHighLevelClient(builder);
        return restHighLevelClient;
    }
}

8.模拟测试

接下来通过JUnit的方式来测试

8.1索引测试

1.新建测试类EsIndexTest

package springframework.springframework;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import springframework.springframework.entity.Product;

@RunWith(SpringRunner.class)
@SpringBootTest
public class EsIndexTest {

    //注入 ElasticsearchRestTemplate
    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    //创建索引并增加映射配置
    @Test
    public void createIndex(){
        //创建索引,系统初始化会自动创建索引
        System.out.println("创建索引");
    }

    @Test
    public void deleteIndex(){
        //创建索引,系统初始化会自动创建索引
        boolean flg = elasticsearchRestTemplate.deleteIndex(Product.class);
        System.out.println("删除索引 = " + flg);
    }

}

2.基于spring-data的方式,在工程启动的时候,会自动读取实体类相关的注解,自动完成索引的创建,运行下创建索引的测试方法。

3.通过ES客户端界面查询确认数据是否新建成功

8.2文档测试

1.新建文档测试类EsDocTest(该测试类中列举了常用的增删改查操作)

package springframework.springframework;

import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.test.context.junit4.SpringRunner;

import springframework.springframework.dao.ProductDao;
import springframework.springframework.entity.Product;

import java.util.ArrayList;
import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class EsDocTest {


    @Autowired
    private ProductDao productDao;

	/**
	 * 新增
	 */
    @Test
    public void save() {
        Product product = new Product();
        product.setId(2L);
        product.setTitle("ipad mini");
        product.setCategory("ipad");
        product.setPrice(1998.0);
        product.setImages("http://ipad.jpg");
        productDao.save(product);
    }


    //修改
    @Test
    public void update(){
        Product product = new Product();
        product.setId(2L);
        product.setTitle("iphone");
        product.setCategory("mobile");
        product.setPrice(6999.0);
        product.setImages("http://www.phone.jpg");
        productDao.save(product);
    }

    //根据 id 查询
    @Test
    public void findById(){
        Product product = productDao.findById(2L).get();
        System.out.println(product);
    }

    //查询所有
    @Test
    public void findAll(){
        Iterable<Product> products = productDao.findAll();
        for (Product product : products) {
            System.out.println(product);
        }
    }

    //删除
    @Test
    public void delete(){
        Product product = new Product();
        product.setId(2L);
        productDao.delete(product);
    }

    //批量新增
    @Test
    public void saveAll(){
        List<Product> productList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            Product product = new Product();
            product.setId(Long.valueOf(i));
            product.setTitle("iphone" + i);
            product.setCategory("mobile");
            product.setPrice(5999.0 + i);
            product.setImages("http://www.phone.jpg");
            productList.add(product);
        }
        productDao.saveAll(productList);
    }

    //分页查询
    @Test
    public void findByPageable(){
        //设置排序(排序方式,正序还是倒序,排序的 id)
        Sort sort = Sort.by(Sort.Direction.DESC,"id");
        int currentPage=0;//当前页,第一页从 0 开始, 1 表示第二页
        int pageSize = 5;//每页显示多少条
        //设置查询分页
        PageRequest pageRequest = PageRequest.of(currentPage, pageSize,sort);
        //分页查询
        Page<Product> productPage = productDao.findAll(pageRequest);
        for (Product Product : productPage.getContent()) {
            System.out.println(Product);
        }
    }

    /**
     * term 查询
     * search(termQueryBuilder) 调用搜索方法,参数查询构建器对象
     */
    @Test
    public void termQuery(){
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", "iphone");
        Iterable<Product> products = productDao.search(termQueryBuilder);
        for (Product product : products) {
            System.out.println(product);
        }
    }

    /**
     * term 查询加分页
     */
    @Test
    public void termQueryByPage(){
        int currentPage= 0 ;
        int pageSize = 5;
        //设置查询分页
        PageRequest pageRequest = PageRequest.of(currentPage, pageSize);
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", "phone");
        Iterable<Product> products =
                productDao.search(termQueryBuilder,pageRequest);
        for (Product product : products) {
            System.out.println(product);
        }
    }

}

2.测试其中批量新增的方法

3.通过ES客户端界面查询确认数据是否批量新增成功

9.小结

更多丰富的API接口的使用有兴趣的同学可以基于在宏哥的基础继续深入的研究学习。

讨论这个帖子(0)垃圾回帖将一律封号处理……