ES总结六:java API
<p>[TOC]</p>
<h1>简介</h1>
<p>我们在前面提到过Elasticsearch底层依赖于Lucene库,而Lucene库完全是Java编写的,RESTflilAPI发送的请求最后都是通过Java执行的。就可行性来讲,JavaAPI比RESTfiilAPI功能更强大。不论是文档的CRUD查询、批量操作、统计操作,还是获取集群信息、索引和集群管理,java都可以做到。</p>
<h1>maven依赖</h1>
<pre><code class="language-java"><dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>{version}</version>
</dependency></code></pre>
<h1>连接到集群</h1>
<p>Elasticsearch的Javaclient对象可以执行多种操作:</p>
<ul>
<li>在现有的群集上执行标准的indexgetdelete和search操作。</li>
<li>在运行的群集上执行管理任务。</li>
</ul>
<p>获得一个Elasticsear chclient对象非常简单,最常用的方式是创建一个可以连接到Elasticsearch集群的传输机对象TransportClient。
需要注意的是,client对象一定要和集群中的节点具有相同的版本,如果客户端和服务器版本不一致,就会导致有些功能无法使用,最理想的情况是客户端和服务器版本保持一致。</p>
<h2>传输机连接</h2>
<p>使用TransportClient创建的client对象可以通过传输模块远程与Elasticsearch集群建立连接。<strong>这种方式只会连接到集群而不会加入集群</strong>,client对象知道一个或多个传输地址,通过轮询调度的方式和服务器交互</p>
<pre><code class="language-java">TransportClient client = new PreBuiltTransportClient(Settings.EMPTY) .addTransportAddress(newInetSocketTransportAddress
(InetAcidress.getByName("hostl"),9300))
.addTransportAddress(newInetSocketTransportAddress
(InetAddress.getByName("host2"),9300));</code></pre>
<p>Settings对象中可以添加配置信息。如果在配置文件中设置的Elasticsearch集群名称不是默认的elasticsearch,就需要在Settings对象中指定集群名称:</p>
<pre><code class="language-java">Settings settings=Settings.builder().put("cluster.name","myClusterName")
.build();
TransportClient client = new PreBuiltTransportClient(settings);</code></pre>
<p>TransportClient对象自带集群探测功能,可以自动添加新的主机、自动移除旧的主机。如果想要打开集群探测功能,就需要设置client.transport.sniff的属性为true:</p>
<pre><code class="language-java">Settings settings=Settings.builder().put("client.transport.sniff",true)
.build();
TransportClient client = new PreBuiltTransportClient(settings);</code></pre>
<p>更多TransportClient的配置如下。
•client.transport.ignoreclustername 设为true会忽略节点的集群名称验证。•client.transport.pingtimeout 设置ping命令的响应时间,默认5秒。•client.transport.nodessamplerinterval 设置检查节点可用性的频率,默认值是5秒。</p>
<h2>节点连接</h2>
<p>节点连接的思路是把应用程序作为Elasticsearch的一个节点,我们的应用程序作为Elasticsearch集群的一部分,客户端作为一个新的节点和集群中的其他节点建立连接。这样可以减少客户端和服务器之间的交互次数,但是这种方法并不总是可行,比如集群不在同一个局域网中。推荐使用传输机方式创建client对象。</p>
<h2>索引管理</h2>
<p>这一小节介绍如何通过ElasticsearchJavaAPI进行索引的创建、删除、刷新、设置别名、设置mapping等索引管理操作。索引管理是通过一个IndicesAdminClient对象发送各种操作请求,获取IndicesAdminClient对象的方式如下:</p>
<pre><code class="language-java">IndicesAdminClient indicesAdminClient=client.admin().indices();</code></pre>
<p>判断索引是否存在:</p>
<pre><code class="language-java">IndicesExistsResponse exResponse =indicesAdminClient
.prepareExists("indexName").get();</code></pre>
<p>判 断type是 否 存 在:</p>
<pre><code class="language-java">TypesExistsResponse existsResponse=indicesAdminClient
.prepareTypesExists("indexName")
.setTypes("typel","type2")
.get();</code></pre>
<p>创建一个索引,索引名必须小写</p>
<pre><code class="language-java">CreateIndexResponse cResponse=indicesAdminClient
.prepareCreate("indexName").get();</code></pre>
<p>创 建 索 引 并 设 置Settings</p>
<pre><code class="language-java">CreateIndexResponse cResponse=indicesAdminClient.prepareCreate("twitter")
.setSettings(Settings.builder()
.put("index.number_of_shards",3)
.put("index.number_of_replicas",2))
.get()</code></pre>
<p>更新副本</p>
<pre><code class="language-java">UpdateSettingsResponse upResponse=indicesAdminClient
.prepareUpdateSettings("twitter")
.setSettings(Settings.builder()
.put("index.number_of_replicas",0))
.get();</code></pre>
<p>设置mapping</p>
<pre><code class="language-java">CreatelndexResponse cResponse=indicesAdminClient
.prepareCreate("twitter")
.addMapping("tweet",XContentFactory.jsonBuilder()
.startObject().startObject("properties")
.startObject("name")
.field("type","keyword")
.endObject().endObject().endObject())
.get();</code></pre>
<p>获取mapping</p>
<pre><code class="language-java">GetMappingsResponse mResponse=indicesAdminClient
.prepareGetMappings("indexname").get();
ImmutableOpenMap<String/MappingMetaData>mapings=mResponse.getMappings()
.get("indexname");
MappingMetaDatametatda=mapings.get("typename");</code></pre>
<p>删 除 索 引</p>
<pre><code class="language-java">DeleteIndexResponse dResponse=indicesAdminClient.prepareDelete("indexname")
.get();</code></pre>
<p>刷 新</p>
<pre><code class="language-java">indicesAdminClient.prepareRefresh().get();
indicesAdminClient.prepareRefresh("indexname").get();
indicesAdminClient.prepareRefresh("indexname","typename").get();</code></pre>
<p>关 闭 索 引</p>
<pre><code class="language-java">CloselndexResponse clResponse=indicesAdminClient.prepareClose("indexname").get();</code></pre>
<p>打 开 索 引</p>
<pre><code class="language-java">OpenlndexResponseopResponse.prepareOpen("indexname").get();indicesAdminClient</code></pre>
<p>设 置 别 名</p>
<pre><code class="language-java">IndicesAliasesResponse
aResponse=indicesAdminClient.prepareAliases().addAlias("indexName","aliasesName").get();</code></pre>
<p>获 取 别 名</p>
<pre><code class="language-java">GetAliasesResponse gResponse=indicesAdminClient.prepareGetAliases("aliasesname").get();</code></pre>
<h2>文档管理</h2>
<p>新建文档
索引文档API可以把一个JSON格式的文档索引到特定的索引中,并使该文档是可搜索的</p>
<pre><code class="language-java">IndexResponse
//doc1是json化的文档
response=client.preparelndex("twitter","tweet","3").setSource(doc1)</code></pre>
<p>获取文档
GetAPI可以实现通过文档id读取一个JSON格式的文档。下面的例子是读取索引名为twitter类型名为tweetid为1的文档:</p>
<pre><code class="language-java">GetResponse response=client.prepareGet("twitter","tweet","1").get();</code></pre>
<p>GetResponse对象提供的常用方法如下:</p>
<ul>
<li>isExists()如果要读取的文档存在,就返回true,否则返回false</li>
<li>getlndex()返回请求文档的索引名。</li>
<li>getType()返回请求文档的类型名。</li>
<li>getld()返回请求文档的ID</li>
<li>getVersion()返回文档版本信息。</li>
<li>getSourceAsBytes():以二进制数组方式读取文档内容。</li>
<li>getSourceAsMap():以map形式读取文档内容。</li>
<li>getSourceAsString():以文本方式读取文档内容。</li>
<li>isSourceEmpty()判断文档内容是否为空</li>
</ul>
<p>删除文档
和读取文档的API类似,DeleteAPI可以实现通过文档id删除Elasticsearch中的文档,以删除索引名为twitter类型名为tweetid为1的文档为例,代码如下:</p>
<pre><code class="language-java">DeleteResponse response=client.prepareDelete("twitter","tweet","1").get();</code></pre>
<p>DeleteResponse对象提供的常用方法如下。</p>
<ul>
<li>status()删除成功,返回OK;删除失败,返回NOT_FOUND</li>
<li>getType()返回删除请求文档的类型。</li>
<li>getld()返回删除请求文档的ID</li>
<li>getVersion()返回删除请求文档的版本信息</li>
</ul>
<p>更新文档
Elasticsearch提供了多种更新文档的API,主要有使用UpdateRequest对象、使用内嵌脚本、使用prepareUpdate()方法这3种。</p>
<pre><code class="language-java">UpdateRequestUpdateRequest=newUpdateRequest();
UpdateRequest.index("twitter");
UpdateRequest.type("tweet");
UpdateRequest.id(’’1");
UpdateRequest.doc(jsonBuilder().startObject().field("gender","male").endObject());
client.update(UpdateRequest).get();</code></pre>
<p>或者</p>
<pre><code class="language-java">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();</code></pre>
<p>Elasticsearch还支持upsert操作,如果文档存在,就执行修改操作;如果文档不存在,就再创建一个新的文档.。</p>
<h2>搜索详解</h2>
<p>和REST接口的查询DSL一样,Elasticsearch也提供了Java接口的查询DSL构造查询对象的工厂类是QueryBuilders,只要查询语句准备好了就可以使用搜索相关的API。
首先创建一个matchquery的对象:</p>
<pre><code class="language-java">QueryBuilder matchQuery=QueryBuilders.matchQuery("title","Java编程").operator(Operator.AND);</code></pre>
<p>查询</p>
<pre><code class="language-java">SearchResponse response=EsUtils.getSingleTransportClient().prepareSearch("books")
.setQuery(matchQuery).highlighter(highlighter).setSize(100).get();</code></pre>
<p>全文查询
使用ElasticsearchJavaAPI构造各种全文级别查询的例子如下。
•MatchAll</p>
<pre><code class="language-java">QueryBuildermatchAUQuery=QueryBuilders.matchAllQuery();</code></pre>
<p>•match_phrase</p>
<pre><code class="language-java">QueryBuildermatchPhraseQuery=QueryBuilders.matchPhraseQuery("foo","helloworld");</code></pre>
<p>•match_phrase_prefix</p>
<pre><code class="language-java">QueryBuildermatchPhrasePrefixQuery=QueryBuilders.matchPhrasePrefixQuery("foo","hellow");</code></pre>
<p>•multimatch</p>
<pre><code class="language-java">QueryBuildermultiMatchQuery=QueryBuilders.multiMatchQuery("kimchy","user","message");</code></pre>
<p>•common</p>
<pre><code class="language-java">QueryBuildercommonTermsQuery=QueryBuilders.commonTermsQuery("name","kimchy");</code></pre>
<p>•querystring</p>
<pre><code class="language-java">QueryBuilderqueryStringQuery=QueryBuilders.queryStringQuery(n+kimchy-elasticsearch");</code></pre>
<p>•simplequerystring</p>
<pre><code class="language-java">QueryBuilderqb=QueryBuilders.simpleQueryStringQuery("+kimchy-elasticsearch");</code></pre>
<p>词项查询</p>
<p>term</p>
<pre><code class="language-java">QueryBuildertermQuery=QueryBuilders.termQuery("title","java");</code></pre>
<p>terms</p>
<pre><code class="language-java">QueryBuildertermsQuery=QueryBuilders.termsQuery("title","java","python");</code></pre>
<p>range</p>
<pre><code class="language-java">QueryBuilderrangeQuery=QueryBuilders.rangeQuery("price").from(50)</code></pre>
<p>exist</p>
<pre><code class="language-java">QueryBuilderexistsQuery=QueryBuilders.existsQuery("language");</code></pre>
<p>prefix</p>
<pre><code class="language-java">QueryBuilderprefixQuery=QueryBuilders•prefixQuery("description","win");</code></pre>
<p>wildcard</p>
<pre><code class="language-java">QueryBuilderwildcardQuery=QueryBuilders•wildcardQuery("author","张若")</code></pre>
<p>regexp</p>
<pre><code class="language-java">QueryBuilderregexpQuery=QueryBuilders.regexpQuery("author","Br.*")</code></pre>
<p>fuzzy</p>
<pre><code class="language-java">QueryBuilderfuzzyQuery=QueryBuilders.fuzzyQuery("title","javascritp")</code></pre>
<p>type</p>
<pre><code class="language-java">QueryBuildertypeQuery=QueryBuilders•typeQuery("IT");</code></pre>
<p>ids</p>
<pre><code class="language-java">QueryBuilderidsQuery=QueryBuilders.idsQuery().ids("3","5");</code></pre>
<p>复合查询
bool
使用bool查询查找title字段中包含关键词java,并且价格不高于70,description字段可以包含也可以不包含虚拟机的书籍,构造boolQuery的代码如下:</p>
<pre><code class="language-java">QueryBuildermatchQueryl=QueryBuilders.matchQuery("title","Java");
QueryBuildermatchQuery2=QueryBuilders.matchQuery("description","虚拟机");
QueryBuilderrangeQuery=QueryBuilders.rangeQuery("price").gte(70);
QueryBuilderboolQuery=QueryBuilders
.boolQuery()
.must(matchQueryl)
.should(matchQuery2)
.mustNot(rangeQuery);</code></pre>
<h2>聚合查询</h2>
<p>指标聚合,求最小值、求和、求平均值、基本统计、高级统计、基数统计、百分位统计的核心代码如下。</p>
<pre><code class="language-java">MinAggregationBuilderminAgg=AggregationBuilders.min("agg").field("price");
SearchResponseresponse=client.prepareSearch("books").addAggregation(minAgg).execute().actionGet();
Minmin=response.getAggregations().get("agg");
double minValue=min.getValue();</code></pre>
<p>最大值</p>
<pre><code class="language-java">SumAggregationBuilder sumAgg=AggregationBuilders.sum("agg").field("price");</code></pre>
<p>平均</p>
<pre><code class="language-java">AvgAggregationBuilder avgAgg = AggregationBuilders.avg("agg").field("price");</code></pre>
<p>stats</p>
<pre><code class="language-java">StatsAggregationBuilder statsAgg=AggregationBuilders.stats("agg").field("price");</code></pre>
<p>Extended Stats</p>
<pre><code class="language-java">ExtendedStatsAggregationBuilder extendedStatsAgg=AggregationBuilders.extendedStats("agg").field("price");</code></pre>
<p>桶聚合
terms</p>
<pre><code class="language-java">TermsAggregationBuildertermAgg=AggregationBuilders.terms("per_count”.field("language");
SearchResponseresponse=EsUtils.getSingleTransportClient()•prepareSearch("books").addAggregation(termAgg).execute().actionGet(); Termsgenders=response.getAggregations().get("per_countn);</code></pre>
<p>filter</p>
<pre><code class="language-java">FilterAggregationBuilderfilterAgg=AggregationBuilders•filter(agg",QueryBuilders.termQuery("title","java"));SearchResponseresponse=client().prepareSearch("books").addAggregation(filterAgg).execute().actionGet();
Filteragg=response.getAggregations().get("agg");</code></pre>
<h1>集群管理</h1>
<p>和索引管理类似,集群管理通过创建ClusterAdminClient对象可以获取集群和索引的健康状态、集群状态。</p>
<pre><code class="language-java">ClusterHealthResponsehealths=client().admin()•cluster().prepareHealth().get();
StringclusterName=intnumberOfDataNodeshealths.getClusterName();
healths.getNumberOfDataNodes();
intnumberOfNodes=healths.getNumberOfNodes();</code></pre>