<p dir="auto">Using elasticsearch java api 1.4.3, I think I'm experiencing a problem similar to what I reported at <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="54818603" data-permission-text="Title is private" data-url="https://github.com/yakaz/elasticsearch-action-updatebyquery/issues/27" data-hovercard-type="issue" data-hovercard-url="/yakaz/elasticsearch-action-updatebyquery/issues/27/hovercard" href="https://github.com/yakaz/elasticsearch-action-updatebyquery/issues/27">yakaz/elasticsearch-action-updatebyquery#27</a> but this time it is the official API that seem to have the issue:</p>
<div class="highlight highlight-source-scala notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="val qb = QueryBuilders.constantScoreQuery(FilterBuilders.termFilter(&quot;user&quot;, &quot;kimchy&quot;))
// returns false, which is expected because I have no such document in my index
client.prepareExists(&quot;myIndex&quot;)
      .setTypes(&quot;myType&quot;)
      .setQuery(qb)
      .execute().actionGet().exists()

// returns true... for any query with an empty (but existing) index/type, which is obviously wrong
client.exists(client.prepareExists(&quot;myIndex&quot;)
      .setTypes(&quot;myType&quot;)
      .setQuery(qb)
      .request()).actionGet().exists()"><pre class="notranslate"><span class="pl-k">val</span> <span class="pl-v">qb</span> <span class="pl-k">=</span> <span class="pl-en">QueryBuilders</span>.constantScoreQuery(<span class="pl-en">FilterBuilders</span>.termFilter(<span class="pl-s"><span class="pl-pds">"</span>user<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>kimchy<span class="pl-pds">"</span></span>))
<span class="pl-c"><span class="pl-c">//</span> returns false, which is expected because I have no such document in my index</span>
client.prepareExists(<span class="pl-s"><span class="pl-pds">"</span>myIndex<span class="pl-pds">"</span></span>)
      .setTypes(<span class="pl-s"><span class="pl-pds">"</span>myType<span class="pl-pds">"</span></span>)
      .setQuery(qb)
      .execute().actionGet().exists()

<span class="pl-c"><span class="pl-c">//</span> returns true... for any query with an empty (but existing) index/type, which is obviously wrong</span>
client.exists(client.prepareExists(<span class="pl-s"><span class="pl-pds">"</span>myIndex<span class="pl-pds">"</span></span>)
      .setTypes(<span class="pl-s"><span class="pl-pds">"</span>myType<span class="pl-pds">"</span></span>)
      .setQuery(qb)
      .request()).actionGet().exists()</pre></div>
<p dir="auto">I think <code class="notranslate">ExistsRequestBuilder.request()</code> is the problem here and I need to get an ExistsRequest as it is what my elasticsearch wrapper expects.</p>
<p dir="auto">Today we have 3 flavors for each endpoint (for demonstration purpose I only use the <code class="notranslate">_health</code> API)</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="public interface ClusterAdminClient extends ElasticsearchClient&lt;ClusterAdminClient&gt; {

    ActionFuture&lt;ClusterHealthResponse&gt; health(ClusterHealthRequest request);

    void health(ClusterHealthRequest request, ActionListener&lt;ClusterHealthResponse&gt; listener);

    ClusterHealthRequestBuilder prepareHealth(String... indices);"><pre class="notranslate"><span class="pl-k">public</span> <span class="pl-k">interface</span> <span class="pl-smi">ClusterAdminClient</span> <span class="pl-k">extends</span> <span class="pl-smi">ElasticsearchClient</span>&lt;<span class="pl-smi">ClusterAdminClient</span>&gt; {

    <span class="pl-smi">ActionFuture</span>&lt;<span class="pl-smi">ClusterHealthResponse</span>&gt; <span class="pl-en">health</span>(<span class="pl-smi">ClusterHealthRequest</span> <span class="pl-s1">request</span>);

    <span class="pl-smi">void</span> <span class="pl-en">health</span>(<span class="pl-smi">ClusterHealthRequest</span> <span class="pl-s1">request</span>, <span class="pl-smi">ActionListener</span>&lt;<span class="pl-smi">ClusterHealthResponse</span>&gt; <span class="pl-s1">listener</span>);

    <span class="pl-smi">ClusterHealthRequestBuilder</span> <span class="pl-en">prepareHealth</span>(<span class="pl-smi">String</span>... <span class="pl-s1">indices</span>);</pre></div>
<p dir="auto">At least one of them is redundant here already but lemme first explain what is trappy here. If you use the <code class="notranslate">prepareHealth().setWaitForGreenStatus()</code> basically nothing happens. you need to call <code class="notranslate">.get()</code> or <code class="notranslate">.execute().get()</code> or <code class="notranslate">.actionGet()</code> or any of the X flavors. This is not so much of a problem for health because you are waiting for a response, but for endpoints that don't return info that is generally consumed ie. update settings this has in the past lead to so many test bugs that I consider this evil.</p>
<p dir="auto">Yet, I think we should remove this method entirely and detach the Builders entirely from the Client. Today once a builder is created like this:</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="  ClusterHealthRequestBuilder builder = client.prepareHealth().setWaitForGreenStatus()"><pre class="notranslate">  <span class="pl-smi">ClusterHealthRequestBuilder</span> <span class="pl-s1">builder</span> = <span class="pl-s1">client</span>.<span class="pl-en">prepareHealth</span>().<span class="pl-en">setWaitForGreenStatus</span>()</pre></div>
<p dir="auto">it's tied to a client and if you close that client the builder can't be executed. To me if we even keep the builder in the future it should only have a <code class="notranslate">build()</code> method that returns the corresponding request. Then you can call:</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="  ClusterHealthRequestBuilder builder = AdminBuilders.health().setWaitForGreenStatus();
  client.health(builder.build());"><pre class="notranslate">  <span class="pl-smi">ClusterHealthRequestBuilder</span> <span class="pl-s1">builder</span> = <span class="pl-smi">AdminBuilders</span>.<span class="pl-en">health</span>().<span class="pl-en">setWaitForGreenStatus</span>();
  <span class="pl-s1">client</span>.<span class="pl-en">health</span>(<span class="pl-s1">builder</span>.<span class="pl-en">build</span>());</pre></div>
<p dir="auto">which is less trappy... oh wait... <code class="notranslate">client.health(builder.build());</code> returns an <code class="notranslate">ActionFuture&lt;ClusterHealthResponse&gt;</code> which is also redundant IMO. We already have a non-blocking API using a listener which is equally powerful.</p>
<p dir="auto">I think what we should move to is this:</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="public interface ClusterAdminClient extends ElasticsearchClient&lt;ClusterAdminClient&gt; {

    ClusterHealthResponse health(ClusterHealthRequest request);

    void health(ClusterHealthRequest request, ActionListener&lt;ClusterHealthResponse&gt; listener);
"><pre class="notranslate"><span class="pl-k">public</span> <span class="pl-k">interface</span> <span class="pl-smi">ClusterAdminClient</span> <span class="pl-k">extends</span> <span class="pl-smi">ElasticsearchClient</span>&lt;<span class="pl-smi">ClusterAdminClient</span>&gt; {

    <span class="pl-smi">ClusterHealthResponse</span> <span class="pl-en">health</span>(<span class="pl-smi">ClusterHealthRequest</span> <span class="pl-s1">request</span>);

    <span class="pl-smi">void</span> <span class="pl-en">health</span>(<span class="pl-smi">ClusterHealthRequest</span> <span class="pl-s1">request</span>, <span class="pl-smi">ActionListener</span>&lt;<span class="pl-smi">ClusterHealthResponse</span>&gt; <span class="pl-s1">listener</span>);</pre></div>
<p dir="auto">that way it's clearly a blocking API and it's easy to use. We still keep the builder (for now ;) ) but remove it's coupling to the client which is super trappy.</p>