我尝试使用Java编写的Elasticsearch API
動機
在使用Java实现Elasticsearch API时,虽然基本用法可以在Qiita和官方参考文档中找到,但是关于更复杂或更实践的描述和代码的文章很少,因此我决定写这篇文章。
这篇文章的对象是…
-
- Elasticsearch APIをJavaで使って開発をこれから行いたい・行う予定の方
- Elasticsearchビギナーの方
环境(当时的开发环境)
-
- Elasticsearch APIバージョン:7.3.2
-
- Javaバージョン:8
-
- Spring Bootバージョン:1.5.15
- mavenバージョン:2.17
准备
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.3.2</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.3.2</version>
</dependency>
使用上述内容,您将能够使用Elasticsearch的库。
基础库的说明和使用方法
这里列出的列名、字段名和ID等,并不都是真实存在的。
搜索请求
当将英文参考资料翻译成中文时
搜索请求(SearchRequest)用于执行对文档、聚合和建议进行搜索操作,并提供请求以高亮显示所获得的文档的方法。
但是,据我所知,它是使用API向Elasticsearch发送请求的基础。
SearchRequest searchRequest = new SearchRequest();
参考:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/master/java-rest-high-search.html
请参考此链接:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/master/java-rest-high-search.html
搜索源构建器
SearchSourceBuilder 是用于添加搜索参数的工具。
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
请参考以下链接获取更多关于Java REST High Level Client的信息:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/master/java-rest-high-search.html
高级客户端
RestHighLevelClient是一个被推荐使用的REST客户端,用于取代之前使用的TransportClient。
通过使用它,你可以从你的Java应用程序通过HTTP访问Elasticsearch。
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials("user", "password")
);
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(new HttpHost("localhost", 9200, "https"))
.setHttpClientConfigCallback(httpAsyncClientBuilder -> httpAsyncClientBuilder
.setDefaultCredentialsProvider(credentialsProvider))
);
searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
可以参考以下链接了解有关Java REST客户端的基本身份验证:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/_basic_authentication.html
得分查询函数
在函数部分中,可以写入多个条件(函数)到score query中,并使用每个条件的得分总和进行排序。
FunctionScoreQueryBuilder functionScoreQueryBuilder = null;
ArrayList<FunctionScoreQueryBuilder.FilterFunctionBuilder> functionScoreArrayList = new ArrayList<>();
// 複数addしてもOK
filterFunctionList.add(
new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.termQuery("FashionItemId", "1"),
ScoreFunctionBuilders.fieldValueFactorFunction("custom_score.").factor(Float.valueOf("0.0254389"
)).missing(0.2)));
// ArrayList型をFunctionScoreQueryBuilder.FilterFunctionBuilder[]にする
FunctionScoreQueryBuilder.FilterFunctionBuilder[] functions = functionScoreArrayList.toArray(new FunctionScoreQueryBuilder.FilterFunctionBuilder[functionScoreArrayList.size()]);
functionScoreQueryBuilder = new FunctionScoreQueryBuilder(queryBuilder, functions).scoreMode(FunctionScoreQuery.ScoreMode.SUM).boostMode(CombineFunction.REPLACE);
searchSourceBuilder.query(functionScoreQueryBuilder);
※FunctionScoreQueryBuilder在中文的参考文章真的很少……。
参考链接:https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html
请看此链接,其中详细介绍了有关使用函数打分查询的信息。
计数
可以使用 .count 方法来操作 RestHighLevelClient。
CountResponse countResponse = null;
countResponse = restHighLevelClient.count(searchRequest, RequestOptions.DEFAULT);
如果采用searchRequest,则可以以CountResponse的格式获取命中数。
参考:https://www.elastic.co/guide/en/elasticsearch/reference/current/search-count.html
请参考上述链接了解如何在Elasticsearch中进行搜索计数。
搜索
您可以通过.search来指定对于RestHighLevelClient的操作。
SearchResponse searchResponse = null;
searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
如果搜索请求成功匹配,那么您可以以SearchResponse的格式获取到搜索结果。
请参考:https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html
请用中文将下面的内容进行转述,只需要一种选择:
_来源
Elasticsearch 的 _source 相当于 SQL 中的 SELECT 语句。
对于 API,可以使用 fetchSource 来指定要获取的字段。
通过缩小获取的字段范围可以减少数据量,从而提高速度。
将要获取的字段作为第一个参数,要排除的字段作为第二个参数进行指定。
在前面提到的 count 的情况下,不需要进行指定。
searchSourceBuilder.fetchSource(new String[]{"FashionItemId", "ItemPrice", "FashionItemSize",
"FashionItemLargeCategory", "FashionItemSmallCategory"},
"ExclusionFashionItemId");
请参考以下链接查阅:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high-search.html#_source_filtering
分类
用于SQL中的”Order By”语句。
通过使用FieldSortBuilder来指定排序。
return searchSourceBuilder.sort(new FieldSortBuilder("ItemPrice").order(SortOrder.ASC))
.sort(new FieldSortBuilder("FashionItemId").order(SortOrder.DESC))
.sort(new FieldSortBuilder("StartDatetime").order(SortOrder.DESC));
参考:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high-search.html#_specifying_sorting
参考文献:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high-search.html#_排序说明
从哪里和尺寸
在SQL中,相当于offset和limit的是什么。
可以在前面提到的SearchSourceBuilder中使用.from和.to来指定。
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.from(0);
searchSourceBuilder.size(100);
请参考以下链接:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/master/java-rest-high-search.html#_using_the_searchsourcebuilder
布尔查询
为了组合其他查询,可以使用。
可以组合AND、OR、NOT。
BoolQuery有4种类型。
典型的搜索查询
术语查询
是否匹配。相当于SQL中的“等于”。
参考:https://www.elastic.co/guide/en/elasticsearch/reference/7.8/query-dsl-term-query.html
查询的条件
在中国的本地语言中使用合适的短语表达,只需一种选项:
是否存在相匹配的项。类似于SQL中的IN条件句
参考:https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-term-level-queries.html#java-query-dsl-terms-query
范围查询
在指定范围内是否存在某些内容。就像SQL中的 >=、<=、<、>所表示的意思一样。
参考:https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-term-level-queries.html#java-query-dsl-range-query
例(SQL与ElasticSearch与Java的比较)
AND StartDatetime >= '2019-12-06 17:33:18'
AND (
(
FashionItemLargeCategory <> 1
AND FashionItemSmallCategory NOT IN (10,20,30)
AND FashionItemSize IN (1,2)
) OR (
(
FashionItemLargeCategory = 2
OR FashionItemSmallCategory IN (40,50,60)
)
AND FashionItemSize IN (9,10)
)
)
"bool": {
"filter": [
{
"range": {
"StartDatetime": {
"from": null,
"to": "2019-12-06 17:33:18",
"include_lower": true,
"include_upper": false
}
}
},
{
"bool": {
"filter": [
{
"bool": {
"should": [
{
"bool": {
"filter": [
{
"terms": {
"FashionItemSize ": [
1,
2
]
}
}
],
"must_not": [
{
"term": {
"FashionItemLargeCategory ": {
"value": 1,
"boost": 1
}
}
},
{
"terms": {
"FashionItemSmallCategory ": [
10,
20,
30
]
}
}
]
}
},
{
"bool": {
"filter": [
{
"terms": {
"FashionItemSize": [
9,
10
]
}
}
],
"should": [
{
"term": {
"FashionItemLargeCategory ": {
"value": 1
}
}
},
{
"terms": {
"FashionItemSmallCategory ": [
40,
50,
60
]
}
}
]
}
}
]
}
}
]
}
}
]
}
这个非常复杂,看起来很难理解……。
integer[] smallCategories1 = {10, 20, 30};
integer[] itemSize1 = {1, 2};
integer[] smallCategories2 = {40, 50, 60};
integer[] itemSize2 = {9, 10};
BoolQueryBuilder qb1 = boolQuery()
.mustNot(termQuery("FashionItemLargeCategory", 1))
.mustNot(termsQuery("FashionItemSmallCategory", smallCategories1))
.filter(termsQuery("FashionItemSize" , itemSize1));
BoolQueryBuilder qb2 = boolQuery()
.should(termQuery("FashionItemLargeCategory", 2))
.should(termsQuery("FashionItemSmallCategory", smallCategories2))
.filter(termsQuery("FashionItemSize", itemSize2));
BoolQueryBuilder qb3 = boolQuery()
.should(qb1)
.should(qb2);
BoolQueryBuilder qb4 = boolQuery()
.filter(rangeQuery("StartDatetime").from(null).lt("2019-12-06 17:33:18"))
.filter(qb3);
验证方法
通过对BoolQueryBuilder执行toString()操作,可以获取Elasticsearch查询。你可以将结果与预期查询进行对比,或在Kibana中运行查询以确认查询是否正确。
System.out.println(qb4.toString());
最后
這篇文章僅僅是描述我第一次接觸Elasticsearch API時的一些資訊。
當時的文章非常有限,但現在調查一下就能找到許多高質量的文章。
如果能對初次接觸Elasticsearch API的人提供一點參考,我會很高興。