我尝试使用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种类型。

クエリ説明mustSQLでいうANDです。指定された条件によってスコアが計算されます。filterSQLでいうANDです。mustと違いスコアが計算されません。shouldSQLでいうORです。must notSQLでいうNOTです。

典型的搜索查询

术语查询

是否匹配。相当于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的人提供一點參考,我會很高興。

广告
将在 10 秒后关闭
bannerAds