Elasticsearch 2.0 + Kibana 4.2使ってみてるよ

そしてハマってるよ

いかメモ

server : Amazon EC2 2台
ES:1.4.2 → 2.0.0
KB:4.1.2 → 4.2.0 + elastic/sense

解決したこと

* ES:bin/pluginのオプションが変わった<code>-i</code>などがなくなり<code>install</code>じゃないとダメ
* （記憶があいまいだけど）以前は<code>bin/plugin -r mobz/elasticsearch-head</code>でpluginをRemoveしていたと思うが、<code>bin/plugin remove mobz/elasticsearch-head</code>はダメで、<code>bin/plugin remove head</code>が正解。
* <code>bin/plugin install elasticsearch/elasticsearch-cloud-aws/hogehoge</code>ではなく<code>bin/plugin install cloud-aws</code>
* HQプラグインがうんともすんとも言わない。
  * HQ -> hq urlも小文字でした。
* elasticsearch.yml に network.host:0.0.0.0 と書かないとノードが見つからない。外から9200が見れない。
* kibana terms AggregationのInclude/Excludeの挙動が変わった<code>^query=.+</code>としていたが<code>query=.+</code>としないと当たらない。
* 1.x系のJavaクライアントでは、2.x系のサーバにつなぐことができない。一部のクラスタを2.x系にすることがかなり難しい。-> 2.0系クラスタへの問い合わせを全てHTTP REST APIを使うことにしてしのぐ。
  * 1.x系のClientである1.6.2が読み込まれいている状態だと、QueryBuildersやFilterBuildersで作ったクエリオブジェクトは。toString()することでJSONになるので、もともとのクエリはこれを使う。
  * 一方で、AggregationBuildersで作ったオブジェクトはtoString()してもJSON文字列は返ってこない（なんで。。。）なのでこちらは書き直し。
  * 参考までに示すと以下のような感じになる。(ソース抜粋して適当にいじったので、このまま貼り付けてもたぶん動かない)なお、この部分はもともと5行くらいで書かれていた。

```java
    /* remote aggregation */
    // private static final DateHistogramBuilder RemoteAggregation = AggregationBuilders.dateHistogram("span").field("@timestamp").interval(Interval.minutes(10)).subAggregation(AggregationBuilders.terms("remote").field("remote").size(100000));
    // @formatter:off
    private static final String RemoteAggregationStr = 
    "\"span\":{"+
      "\"date_histogram\":{"+
        "\"field\":\"@timestamp\","+
        "\"interval\":\"10m\""+
      "},"+
      "\"aggs\":{"+
        "\"remote\":{"+
          "\"terms\":{"+
            "\"field\":\"remote\","+
            "\"size\":100000"+
          "}"+
        "}"+
      "}"+
    "}";
    // @formatter:on

    private DateHistogram search (FilteredQueryBuilder queryFilter) {
       HttpClient httpClient = HttpClientBuilder.create().build();
       // @formatter:off
       String queryStr = 
               "{"+
               "  \"query\":" + queryFilter.toString() + "," +
               "  \"size\":0,"+
               "  \"aggs\":{" +
               "    " + RemoteAggregationStr +
               "  }"+
               "}";
       HttpUriRequest post = RequestBuilder.post(
         "http://your.es.server.host:9200/logstash-active-last-2-months/_search"
       ).setHeader("Content-Type",ContentType.APPLICATION_JSON.getMimeType())
       .setEntity(
         new StringEntity(
           queryStr,
           "UTF-8"
         )
       ).build();
       DateHistogram spanAgg = null;
       // @formatter:on
       try {
           HttpResponse response = httpClient.execute(post);
           int code = response.getStatusLine().getStatusCode();
           if (code != 200) {
               logger.log(ERROR.ACCESS_LOG_SERVER_HTTP_REST_API_ERROR, response.getStatusLine().toString());
               logger.log(DEBUG, queryStr);
           }else{
               JsonParser parser = new JsonFactory().createJsonParser(response.getEntity().getContent());
               ObjectMapper mapper = new ObjectMapper();
               JsonNode root = mapper.readTree(parser);
               spanAgg = new DateHistogram() {

                   // @formatter:off
                   public String getName() { return "span";}
                   public List<? extends Bucket> getBuckets() {
                       return new ArrayList<Bucket>() {
                           {
                               JsonNode span = root.get("aggregations").get("span");
                               span.get("buckets").elements().forEachRemaining(bucket->{
                                   this.add(new DateHistogram.Bucket(){
                                       public Number getKeyAsNumber()        {return bucket.get("key").asLong();}
                                       public String getKey()                 {return new Date(bucket.get("key").asLong()).toString();}
                                       public Text getKeyAsText()            {return new StringText(new Date(bucket.get("key").asLong()).toString());}
                                       public long getDocCount()             {return bucket.get("doc_count").asLong();}
                                       public Aggregations getAggregations() {
                                           JsonNode remote = bucket.get("remote");
                                           return new InternalAggregations(new ArrayList<InternalAggregation>(){
                                               {
                                                   List<InternalTerms.Bucket> buckets = new ArrayList<InternalTerms.Bucket>();
                                                   remote.get("buckets").elements().forEachRemaining(_bucket->{
                                                       buckets.add(new StringTerms.Bucket(new BytesRef(_bucket.get("key").asText()), _bucket.get("doc_count").asLong(), null, false, 0));
                                                   });
                                                   this.add(
                                                     new StringTerms("remote", Terms.Order.count(false), 1000, 1000, 0, buckets, false, 0, 0)
                                                   );
                                               }
                                           });
                                       }
                                       public DateTime getKeyAsDate()        {return null;}
                                   });
                               });
                           }
                       };
                   }
                   public Bucket getBucketByKey(String key) {return null;}
                   public Bucket getBucketByKey(Number key) {return null;}
                   public Bucket getBucketByKey(DateTime key) {return null;}
                   // @formatter:on
               };
           }
       } catch (IOException e) {
           logger.log(ERROR.ACCESS_LOG_JSON_PARSE_ERROR, "accesslog parse error", e);
       }
       return spanAgg;
    }
```
  * ↑AggregationもJsonで取れるかもしれない。1.6.2クラアント->2.0.0サーバの接続がエラーになるのは、executeしたタイミングっぽい。なので、executeせずにprepareSearch().setQuery().addAggregation()で返されるオブジェクトが利用できるかも。後で調べる。
  * あ、そういえば、調べればわかることだけど、TermsFilter使っている場合、AND条件にはできない。無視されてOR条件になるので注意。
    * Boolフィルターに変えるといったん対応できる。

まだ解決してないこと

* KibanaをKibanaUserなどroot以外で立ち上げるようにすると、permission error系の現象が多発する。<code>kibana-4.2.0-linux-x64.tar.gz</code>をそのまま展開すると、所有者のみの読み込み権限があるディレクトリがあるのはchmodやchownして解決できるが、<code>/usr/share/elasticsearch/.babel.json</code>をKibana起動時に書き込みに行くのはどうしようね。(もしかしてelastic/senseのせい？？)
* _shutdown APIがなくなってる。。。
* 単純には切り戻せない。。。
  *  1.4.2->2.0.0->1.4.2 インデックス見つからない
  *  1.4.2->2.0.0->1.7.3 起動しない

パーミッションはElasticsearchはパッケージでの提供で、Kibanaがtar.gzでの提供なのが悪いのか