ES总结六:java API

简介

我们在前面提到过Elasticsearch底层依赖于Lucene库,而Lucene库完全是Java编写的,RESTflilAPI发送的请求最后都是通过Java执行的。就可行性来讲,JavaAPI比RESTfiilAPI功能更强大。不论是文档的CRUD查询、批量操作、统计操作,还是获取集群信息、索引和集群管理,java都可以做到。

maven依赖

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>transport</artifactId>
    <version>{version}</version>
</dependency>

连接到集群

Elasticsearch的Javaclient对象可以执行多种操作:

  • 在现有的群集上执行标准的indexgetdelete和search操作。
  • 在运行的群集上执行管理任务。

获得一个Elasticsear chclient对象非常简单,最常用的方式是创建一个可以连接到Elasticsearch集群的传输机对象TransportClient。
需要注意的是,client对象一定要和集群中的节点具有相同的版本,如果客户端和服务器版本不一致,就会导致有些功能无法使用,最理想的情况是客户端和服务器版本保持一致。

传输机连接

使用TransportClient创建的client对象可以通过传输模块远程与Elasticsearch集群建立连接。这种方式只会连接到集群而不会加入集群,client对象知道一个或多个传输地址,通过轮询调度的方式和服务器交互

TransportClient client = new PreBuiltTransportClient(Settings.EMPTY)    .addTransportAddress(newInetSocketTransportAddress
(InetAcidress.getByName("hostl"),9300))
.addTransportAddress(newInetSocketTransportAddress
(InetAddress.getByName("host2"),9300));

Settings对象中可以添加配置信息。如果在配置文件中设置的Elasticsearch集群名称不是默认的elasticsearch,就需要在Settings对象中指定集群名称:

Settings settings=Settings.builder().put("cluster.name","myClusterName")
.build();
TransportClient client = new PreBuiltTransportClient(settings);

TransportClient对象自带集群探测功能,可以自动添加新的主机、自动移除旧的主机。如果想要打开集群探测功能,就需要设置client.transport.sniff的属性为true:

Settings settings=Settings.builder().put("client.transport.sniff",true)
.build();
TransportClient client = new PreBuiltTransportClient(settings);

更多TransportClient的配置如下。
•client.transport.ignoreclustername 设为true会忽略节点的集群名称验证。•client.transport.pingtimeout 设置ping命令的响应时间,默认5秒。•client.transport.nodessamplerinterval 设置检查节点可用性的频率,默认值是5秒。

节点连接

节点连接的思路是把应用程序作为Elasticsearch的一个节点,我们的应用程序作为Elasticsearch集群的一部分,客户端作为一个新的节点和集群中的其他节点建立连接。这样可以减少客户端和服务器之间的交互次数,但是这种方法并不总是可行,比如集群不在同一个局域网中。推荐使用传输机方式创建client对象。

索引管理

这一小节介绍如何通过ElasticsearchJavaAPI进行索引的创建、删除、刷新、设置别名、设置mapping等索引管理操作。索引管理是通过一个IndicesAdminClient对象发送各种操作请求,获取IndicesAdminClient对象的方式如下:

IndicesAdminClient indicesAdminClient=client.admin().indices();

判断索引是否存在:

IndicesExistsResponse exResponse =indicesAdminClient
.prepareExists("indexName").get();

判 断type是 否 存 在:

TypesExistsResponse existsResponse=indicesAdminClient
    .prepareTypesExists("indexName")
    .setTypes("typel","type2")
    .get();

创建一个索引,索引名必须小写

CreateIndexResponse cResponse=indicesAdminClient
    .prepareCreate("indexName").get();

创 建 索 引 并 设 置Settings

CreateIndexResponse cResponse=indicesAdminClient.prepareCreate("twitter")
    .setSettings(Settings.builder()
    .put("index.number_of_shards",3)
    .put("index.number_of_replicas",2))
    .get()

更新副本

UpdateSettingsResponse upResponse=indicesAdminClient
    .prepareUpdateSettings("twitter")
    .setSettings(Settings.builder()
    .put("index.number_of_replicas",0))
    .get();

设置mapping

CreatelndexResponse cResponse=indicesAdminClient
.prepareCreate("twitter")
.addMapping("tweet",XContentFactory.jsonBuilder()
            .startObject().startObject("properties")
            .startObject("name")
            .field("type","keyword")
            .endObject().endObject().endObject())
    .get();

获取mapping

GetMappingsResponse mResponse=indicesAdminClient
.prepareGetMappings("indexname").get();
ImmutableOpenMap<String/MappingMetaData>mapings=mResponse.getMappings()
.get("indexname");
MappingMetaDatametatda=mapings.get("typename");

删 除 索 引

DeleteIndexResponse dResponse=indicesAdminClient.prepareDelete("indexname")
.get();

刷 新

indicesAdminClient.prepareRefresh().get();
indicesAdminClient.prepareRefresh("indexname").get();
indicesAdminClient.prepareRefresh("indexname","typename").get();

关 闭 索 引

CloselndexResponse clResponse=indicesAdminClient.prepareClose("indexname").get();

打 开 索 引

OpenlndexResponseopResponse.prepareOpen("indexname").get();indicesAdminClient

设 置 别 名

IndicesAliasesResponse
aResponse=indicesAdminClient.prepareAliases().addAlias("indexName","aliasesName").get();

获 取 别 名

GetAliasesResponse gResponse=indicesAdminClient.prepareGetAliases("aliasesname").get();

文档管理

新建文档
索引文档API可以把一个JSON格式的文档索引到特定的索引中,并使该文档是可搜索的

IndexResponse
//doc1是json化的文档
response=client.preparelndex("twitter","tweet","3").setSource(doc1)

获取文档
GetAPI可以实现通过文档id读取一个JSON格式的文档。下面的例子是读取索引名为twitter类型名为tweetid为1的文档:

GetResponse response=client.prepareGet("twitter","tweet","1").get();

GetResponse对象提供的常用方法如下:

  • isExists()如果要读取的文档存在,就返回true,否则返回false
  • getlndex()返回请求文档的索引名。
  • getType()返回请求文档的类型名。
  • getld()返回请求文档的ID
  • getVersion()返回文档版本信息。
  • getSourceAsBytes():以二进制数组方式读取文档内容。
  • getSourceAsMap():以map形式读取文档内容。
  • getSourceAsString():以文本方式读取文档内容。
  • isSourceEmpty()判断文档内容是否为空

删除文档
和读取文档的API类似,DeleteAPI可以实现通过文档id删除Elasticsearch中的文档,以删除索引名为twitter类型名为tweetid为1的文档为例,代码如下:

DeleteResponse response=client.prepareDelete("twitter","tweet","1").get();

DeleteResponse对象提供的常用方法如下。

  • status()删除成功,返回OK;删除失败,返回NOT_FOUND
  • getType()返回删除请求文档的类型。
  • getld()返回删除请求文档的ID
  • getVersion()返回删除请求文档的版本信息

更新文档
Elasticsearch提供了多种更新文档的API,主要有使用UpdateRequest对象、使用内嵌脚本、使用prepareUpdate()方法这3种。

UpdateRequestUpdateRequest=newUpdateRequest();
UpdateRequest.index("twitter");
UpdateRequest.type("tweet");
UpdateRequest.id(’’1");
UpdateRequest.doc(jsonBuilder().startObject().field("gender","male").endObject());
client.update(UpdateRequest).get();

或者

client.prepareUpdate("ttl","doc","1").setScript(newScript("ctx•一source.gender=\"male\"",ScriptService.ScriptType.INLINE,null,null))•get();
client.prepareUpdate("ttl","doc","1").setDoc(jsonBuilder().startObject().field("gender","male").endObject()).get();

Elasticsearch还支持upsert操作,如果文档存在,就执行修改操作;如果文档不存在,就再创建一个新的文档.。

搜索详解

和REST接口的查询DSL一样,Elasticsearch也提供了Java接口的查询DSL构造查询对象的工厂类是QueryBuilders,只要查询语句准备好了就可以使用搜索相关的API。
首先创建一个matchquery的对象:

QueryBuilder matchQuery=QueryBuilders.matchQuery("title","Java编程").operator(Operator.AND);

查询

SearchResponse response=EsUtils.getSingleTransportClient().prepareSearch("books")
.setQuery(matchQuery).highlighter(highlighter).setSize(100).get();

全文查询
使用ElasticsearchJavaAPI构造各种全文级别查询的例子如下。
•MatchAll

QueryBuildermatchAUQuery=QueryBuilders.matchAllQuery();

•match_phrase

QueryBuildermatchPhraseQuery=QueryBuilders.matchPhraseQuery("foo","helloworld");

•match_phrase_prefix

QueryBuildermatchPhrasePrefixQuery=QueryBuilders.matchPhrasePrefixQuery("foo","hellow");

•multimatch

QueryBuildermultiMatchQuery=QueryBuilders.multiMatchQuery("kimchy","user","message");

•common

QueryBuildercommonTermsQuery=QueryBuilders.commonTermsQuery("name","kimchy");

•querystring

QueryBuilderqueryStringQuery=QueryBuilders.queryStringQuery(n+kimchy-elasticsearch");

•simplequerystring

QueryBuilderqb=QueryBuilders.simpleQueryStringQuery("+kimchy-elasticsearch");

词项查询

term

QueryBuildertermQuery=QueryBuilders.termQuery("title","java");

terms

QueryBuildertermsQuery=QueryBuilders.termsQuery("title","java","python");

range

QueryBuilderrangeQuery=QueryBuilders.rangeQuery("price").from(50)

exist

QueryBuilderexistsQuery=QueryBuilders.existsQuery("language");

prefix

QueryBuilderprefixQuery=QueryBuilders•prefixQuery("description","win");

wildcard

QueryBuilderwildcardQuery=QueryBuilders•wildcardQuery("author","张若")

regexp

QueryBuilderregexpQuery=QueryBuilders.regexpQuery("author","Br.*")

fuzzy

QueryBuilderfuzzyQuery=QueryBuilders.fuzzyQuery("title","javascritp")

type

QueryBuildertypeQuery=QueryBuilders•typeQuery("IT");

ids

QueryBuilderidsQuery=QueryBuilders.idsQuery().ids("3","5");

复合查询
bool
使用bool查询查找title字段中包含关键词java,并且价格不高于70,description字段可以包含也可以不包含虚拟机的书籍,构造boolQuery的代码如下:

QueryBuildermatchQueryl=QueryBuilders.matchQuery("title","Java");
QueryBuildermatchQuery2=QueryBuilders.matchQuery("description","虚拟机");
QueryBuilderrangeQuery=QueryBuilders.rangeQuery("price").gte(70);
QueryBuilderboolQuery=QueryBuilders
    .boolQuery()
    .must(matchQueryl)
    .should(matchQuery2)
    .mustNot(rangeQuery);

聚合查询

指标聚合,求最小值、求和、求平均值、基本统计、高级统计、基数统计、百分位统计的核心代码如下。

MinAggregationBuilderminAgg=AggregationBuilders.min("agg").field("price");
SearchResponseresponse=client.prepareSearch("books").addAggregation(minAgg).execute().actionGet();
Minmin=response.getAggregations().get("agg");
double minValue=min.getValue();

最大值

SumAggregationBuilder sumAgg=AggregationBuilders.sum("agg").field("price");

平均

AvgAggregationBuilder avgAgg = AggregationBuilders.avg("agg").field("price");

stats

StatsAggregationBuilder statsAgg=AggregationBuilders.stats("agg").field("price");

Extended Stats

ExtendedStatsAggregationBuilder extendedStatsAgg=AggregationBuilders.extendedStats("agg").field("price");

桶聚合
terms

TermsAggregationBuildertermAgg=AggregationBuilders.terms("per_count”.field("language");
SearchResponseresponse=EsUtils.getSingleTransportClient()•prepareSearch("books").addAggregation(termAgg).execute().actionGet(); Termsgenders=response.getAggregations().get("per_countn);

filter

FilterAggregationBuilderfilterAgg=AggregationBuilders•filter(agg",QueryBuilders.termQuery("title","java"));SearchResponseresponse=client().prepareSearch("books").addAggregation(filterAgg).execute().actionGet();
 Filteragg=response.getAggregations().get("agg");

集群管理

和索引管理类似,集群管理通过创建ClusterAdminClient对象可以获取集群和索引的健康状态、集群状态。

ClusterHealthResponsehealths=client().admin()•cluster().prepareHealth().get();
StringclusterName=intnumberOfDataNodeshealths.getClusterName();
healths.getNumberOfDataNodes();
intnumberOfNodes=healths.getNumberOfNodes();