大家好,我是老坛。

本篇文章全部代码资源请关注同名公众号:老坛聊开发

回复:"7.x模板" 即可获取

Elasticsearch是一个分布式的RESTful 风格的搜索和数据分析引擎,它使用方便,查询速度快,因此也被越来越多的开发人员使用。

在Java项目中,使用ES的场景也十分常见。除了作为某些特定资源的存储之外也可以作为像ELK这样的日志收集系统里的存储引擎。总之,对于非关系型而查找需求较多的场景,ES的表现还是非常不错的。

那今天老坛就带大家看一看如何使用Java API来操作ES。

当前文档只限于ES的版本在7.x及其以下的情况,如果是8.x的可以去看我的另一篇文档:

【ES使用】Java API操作ES宝典(8.x版本)https://blog.csdn.net/qq_34263207/article/details/127847033

目录

1.准备工作

1.1引入依赖

1.2配置文件

2. 简单操作

2.1 插入数据

2.2 查询数据

2.3 修改数据

2.4 删除数据

3 复杂查询

3.1 整体介绍

3.2 QueryBuilder说明

3.2.1 MatchQueryBuilder

3.2.2 MatchPhraseQueryBuilder

3.2.3 MultiMatchQueryBuilder

3.2.4 TermQueryBuilder

3.2.5 TermsQueryBuilder

3.2.6 FuzzyQueryBuilder

3.2.7 RangeQueryBuilder

3.3 bool查询

3.4 排序和分页

4.代码模板

5. 总结


1.准备工作

在真正使用es api之前,还有一些准备工作要去做,分别是引入依赖和写好配置文件

1.1引入依赖

对于7.x及其以下的版本,spring data这边是支持的,所以可以根据自己ES的具体版本来引入匹配版本的spring data starter,具体如下:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

关于如何去查看spring data与ES的版本匹配关系,大家可以去看我的这篇文章,这里便不再赘述了。

【ES知识】es版本与java api版本对照一览https://blog.csdn.net/qq_34263207/article/details/127790216

1.2配置文件

接下来就是去写配置文件了。我们要连接ES所要用到的ip和port,用户名和密码这些信息建议大家都写在自己的yml里,方便维护:

es:
  address: 127.0.0.1
  port: 9200
  scheme: http
  username: admin
  password: admin

接下来我们要写一个config文件来使用这些配置,具体代码如下:

import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ElasticSearchConfig {

    @Value("${es.address}")
    String address;

    @Value("${es.port}")
    Integer port;

    @Value("${es.scheme}")
    String scheme;

    @Value("${es.username}")
    String username;

    @Value("${es.password}")
    String password;

    @Bean
    public RestHighLevelClient esRestClient(){
        RestClientBuilder builder = null;
        builder = RestClient.builder(new HttpHost(address, port, scheme));
        RestHighLevelClient client =  new RestHighLevelClient(builder);
        return client;
    }
}

这个是无用户名和密码版本的配置文件,大家可以直接拿走使用。

下面贴一下需要配置用户名和密码的config文件:

import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ElasticSearchConfig {

    @Value("${es.address}")
    String address;

    @Value("${es.port}")
    Integer port;

    @Value("${es.scheme}")
    String scheme;

    @Value("${es.username}")
    String username;

    @Value("${es.password}")
    String password;

    @Bean
    public RestHighLevelClient esRestClientWithCred(){
        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
        RestClientBuilder restClientBuilder = RestClient.builder(new HttpHost(address, port, scheme))
                .setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
                    @Override
                    public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpAsyncClientBuilder) {
                        return httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
                    }
                });
        RestHighLevelClient esClient = new RestHighLevelClient(restClientBuilder);
        return esClient;
    }
}

按需来取即可。

2. 简单操作

也就是最基本的CRUD了,但是这部分介绍的都是只针对一条数据的CRUD操作,都是通过id来去进行的,比较简单。而操作这些所使用到的类也比较有规律,这里我给大家画一张图方便理解:

 RestHighLevelClient是我们所有操作的核心,它也是在我们config里面写好的,等着被注入就可以了。对于每一种操作都有其相应的request和response,我们在request里面填充需要做的操作,用response接收结果。下面举例来介绍这些操作。

更多优质文章资源请关注同名公众号:老坛聊开发

先介绍一下我用到的实体对象:

@Data
public class TextBook {

    String bookName;

    String author;

    Integer num;
}

对应的索引数据为:

{
    "_index": "textbook",
    "_id": "kIwXeYQB8iTYJNkI986Y",
    "_source": {
        "bookName": "This is a test doc",
        "author": "老坛",
        "num": 20
    }
}

2.1 插入数据

@SpringBootTest
@RunWith(SpringRunner.class)
@Slf4j
public class ESTest {

    @Resource
    RestHighLevelClient restHighLevelClient;

    String index = "index";

    @Test
    public void insertSingle(String id) throws IOException {
        IndexRequest request = new IndexRequest(index);
        request.id(id);
        // 要插入的实体
        TextBook textBook = new TextBook();
        textBook.setBookName("老坛聊开发");
        textBook.setAuthor("老坛");
        textBook.setNum(20);
        request.source(JSON.toJSONString(textBook), XContentType.JSON);
        IndexResponse indexResponse = restHighLevelClient.index(request, RequestOptions.DEFAULT);
        log.info("返回状态:" + indexResponse.status().getStatus());
    }
}

我们需要将RestHighLevelClient注入进来,然后就可以操作了。

2.2 查询数据

@SpringBootTest
@RunWith(SpringRunner.class)
@Slf4j
public class ESTest {

    @Resource
    RestHighLevelClient restHighLevelClient;

    String index = "index";

    @Test
    public void grepSingle(String id) throws IOException {
        GetRequest getRequest = new GetRequest(index);
        getRequest.id(id);
        GetResponse getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
        String json = getResponse.getSourceAsString();
        TextBook textBook = JSONObject.parseObject(json, TextBook.class);
        log.info("返回结果为:" + JSON.toJSONString(textBook));
    }
}

这里是使用id查询单条数据,相当于sql的getByPrimaryKey。

2.3 修改数据

@SpringBootTest
@RunWith(SpringRunner.class)
@Slf4j
public class ESTest {

    @Resource
    RestHighLevelClient restHighLevelClient;

    String index = "index";

    @Test
    public void updateSingle(String id) throws IOException {
        GetRequest getRequest = new GetRequest(index);
        getRequest.id(id);
        // 先查看是否包含该数据,以防报错
        boolean exists = restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT);
        if(exists) {
            UpdateRequest updateRequest = new UpdateRequest(index, id);
            TextBook textBook = new TextBook();
            // 要更新的实体
            textBook.setBookName("老坛聊开发");
            textBook.setAuthor("老坛");
            updateRequest.doc(JSON.toJSONString(textBook), XContentType.JSON);
            UpdateResponse updateResponse = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
            log.info("返回状态:" + updateResponse.status().getStatus());
        }
    }
}

这里先用exist方法查询了一下该条数据是否存在,存在的话再去修改数据。

2.4 删除数据

@SpringBootTest
@RunWith(SpringRunner.class)
@Slf4j
public class ESTest {

    @Resource
    RestHighLevelClient restHighLevelClient;

    String index = "index";

    @Test
    public void deleteSingle(String id) throws IOException {
        DeleteRequest deleteRequest = new DeleteRequest(index);
        deleteRequest.id(id);
        DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
        log.info("返回状态:" + deleteResponse.status().getStatus());
    }
}

3 复杂查询

3.1 整体介绍

下面介绍复杂查询,也是我们比较常用的ES查询方式,这里如果大家有一定的ES语法基础会更方便的理解下面的内容,想了解ES基础语法可以去看我的这篇文章:

【ES知识】ES基础查询语法一览https://blog.csdn.net/qq_34263207/article/details/127849806

老规矩,先上图:

 该图描绘了我们在复杂查询时会涉及到的类:一样是使用RestHighLevelClient,然后通过SearchRequest进行操作,SearchRequest又需要SearchSourceBuilder,而SearchSourceBuilder需要通过QueryBuilder完成构建,图中最下面一行列出了几种常用的QueryBuilder,基本上和我们ES查询的语法是直接相关的。最后SearchResponse返回结果。

更多优质文章资源请关注同名公众号:老坛聊开发

下面给出查询的模板代码:

@SpringBootTest
@RunWith(SpringRunner.class)
@Slf4j
public class ESTest {

    @Resource
    RestHighLevelClient restHighLevelClient;

    String index = "index";

    @Test
    public List<TextBook> grepTextBook() throws IOException {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("author", "老坛");
        searchSourceBuilder.query(matchQueryBuilder);
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(index);
        searchRequest.source(searchSourceBuilder);
        List<TextBook> textBookList = new ArrayList<>();
        //执行操作
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        if (Objects.nonNull(searchResponse)) {
            SearchHits searchHits = searchResponse.getHits();
            for (int i = 0; i < searchHits.getHits().length; i++) {
                String str = searchHits.getHits()[i].getSourceAsString();
                System.out.println(str);
                textBookList.add(JSON.parseObject(str, TextBook.class));
            }
        }
        return textBookList;
    }
}

整个查询代码的核心实际上只有这一行:

MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("author", "老坛");

因为只有QueryBuilder决定了你要怎么去进行查询,其它的都是模板,可以不动。

3.2 QueryBuilder说明

下面我们来一一介绍几种常用的QueryBuilder:

3.2.1 MatchQueryBuilder

MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("author", "老坛");

对应了ES的match查询,它等价的ES语法就是:

GET textbook/_search
{
  "query": {
    "match": {
      "author":"老坛"
    }
  }
}

3.2.2 MatchPhraseQueryBuilder

MatchPhraseQueryBuilder matchPhraseQueryBuilder = QueryBuilders.matchPhraseQuery("bookName", "老坛");

对应了ES的match_phrase查询,它等价的ES语法就是:

GET textbook/_search
{
  "query": {
    "match_phrase": {
      "bookName":"老坛"
    }
  }
}

3.2.3 MultiMatchQueryBuilder

MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("老坛", "author","bookName");

对应了ES的multi_match查询,它等价的ES语法就是:

GET textbook/_search
{
	"query": {
		"multi_match": {
			"query": "老坛",
			"fields": ["author","bookName"]
		}
	}
}

3.2.4 TermQueryBuilder

TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("author", "老坛");

对应了ES的term查询,它等价的ES语法就是:

GET textbook/_search
{
	"query": {
		"term": {
			"author": {
				"value": "老坛"
			}
		}
	}
}

3.2.5 TermsQueryBuilder

TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery("author", "老","坛");

对应了ES的terms查询,它等价的ES语法就是:

GET textbook/_search
{
	"query": {
		"terms": {
			"author": ["老","坛"]
		}
	}
}

3.2.6 FuzzyQueryBuilder

FuzzyQueryBuilder fuzzyQueryBuilder = QueryBuilders.fuzzyQuery("bookName", "老坛");

对应了ES的fuzzy查询,它等价的ES语法就是:

GET textbook/_search
{
    "query":{
        "fuzzy":{
            "bookName":"老坛"
        }
    }
}

我们只要根据自己需要选择不同的builder去查询就可以了

3.2.7 RangeQueryBuilder

RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("num")
                .gt(10)
                .lt(20);

对应了ES的range查询,它等价的ES语法就是:

GET textbook/_search
{
    "query":{
        "range":{
            "num":{
                "lt":20,
                "gt":10
            }
        }
    }
}

更多优质文章资源请关注同名公众号:老坛聊开发

3.3 bool查询

bool查询也是我们使用es中比较常见的,当我们需要查询多个条件时,就会需要:

MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("bookName", "老坛");
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("author", "老坛");
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
    .must(matchQueryBuilder)
    .should(termQueryBuilder);

所对应的ES语法为:

GET textbook/_search
{
    "query":{
        "bool":{
            "must":{
                "match":{
                    "bookName":"老坛"
                }
            },
            "should":{
                "term":{
                    "author":"老坛"
                }
            }
        }
    }
}

3.4 排序和分页

还用最开始的match举例,这里在此基础上添加了排序和分页两个限制:

@SpringBootTest
@RunWith(SpringRunner.class)
@Slf4j
public class ESTest {

    @Resource
    RestHighLevelClient restHighLevelClient;

    String index = "index";

    @Test
    public List<TextBook> grepTextBook() throws IOException {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("bookName", "老坛");
        searchSourceBuilder.query(matchQueryBuilder);
        // 分页参数
        searchSourceBuilder.sort("num", SortOrder.DESC);
        searchSourceBuilder.from(1);
        searchSourceBuilder.size(100);
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(index);
        searchRequest.source(searchSourceBuilder);
        List<TextBook> textBookList = new ArrayList<>();
        //执行操作
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        if (Objects.nonNull(searchResponse)) {
            SearchHits searchHits = searchResponse.getHits();
            for (int i = 0; i < searchHits.getHits().length; i++) {
                String str = searchHits.getHits()[i].getSourceAsString();
                System.out.println(str);
                textBookList.add(JSON.parseObject(str, TextBook.class));
            }
        }
        return textBookList;
    }
}

排序和分页主要体现在这几行:

// 分页参数
searchSourceBuilder.sort("num", SortOrder.DESC);
searchSourceBuilder.from(1);
searchSourceBuilder.size(100);

可以看到这是一个按照num字段的降序搜索,并且是按照页容量为100进行分页,取第二页。

所对应的ES语法为:

GET textbook/_search
{
    "query":{
        "match":{
            "bookName":"老坛"
        }
    },
    "from":0,
    "size":100,
    "sort":{
        "num":{
            "order":"desc"
        }
    }
}

4.代码模板

本篇文章中介绍的全部es操作老坛已整理成模板项目了:

请关注同名公众号:老坛聊开发

并回复:"7.x模板" 获取代码模板

只要大家根据自己的实际环境修改配置即可直接跑起来啦,亲测有效!

5. 总结

到这里Java对ES的操作基本上聊的差不多了,题主这里介绍的未必详尽,只是一些我们通常会用到的操作,如果还想详细了解更多的内容请阅读官方文档:

https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/7.17/java-client-javadoc.html

另外,题主这里只是为了给大家讲明白如何使用举了几个例子,并不一定效率最高或者使用常见最为恰当,还是需要大家学习一下ES的语法根据自己的实际业务场景去选用,谢谢大家~

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐