Querying ElasticSearch from VIM

I'm using ElasticSearch quite a bit and finally decided to make it easy to debug. I now write JSON queries with a .es extension. And have this in my .vim/filetype.vim file:

autocmd! BufRead,BufNewFile *.es      setfiletype elasticsearch

In .vim/ftplugin/elasticsearch.vim I've just added a very minimal setup for ElasticSearch:

if exists("b:did_elastic_search_ftplugin")                                                                                                                                       
  finish                                                                                                                                                                         
endif                                                                                                                                                                            
let b:did_elastic_search_ftplugin = 1                                                                                                                                            

set syntax=json                                                                                                                                                                  
noremap ,r   :!json_check %<cr>

And the finishing piece is my json_check script (which should be renamed):

#!/usr/bin/env perl                                                                                                                                                          

use strict;                                                                                                                                                                  
use warnings;                                                                                                                                                                
use Try::Tiny;                                                                                                                                                               

use JSON;                                                                                                                                                                    
use Term::ANSIColor;                                                                                                                                                         
my $URL = "'http://127.0.0.1:9200/search_engine/DestinationName/_search?preference=_local&pretty=1'";                                                                        

my $json_file = shift or die "Usage: $0 json_file";                                                                                                                          
open my $fh, '<' . $json_file or die "Cannot open $json_file for reading: $!";                                                                                               
my $json = do { local $/; <$fh> };                                                                                                                                           

my $perl;                                                                                                                                                                    
try {                                                                                                                                                                        
    $perl = decode_json $json;                                                                                                                                               
}                                                                                                                                                                            
catch {                                                                                                                                                                      
    if (/character offset ([0-9]+)/) {                                                                                                                                       

        # if we fail and find the offset of the JSON error, show the first                                                                                                   
        # part as white and the second part as red                                                                                                                           
        my $offset = $1;                                                                                                                                                     
        my $before = substr $json, 0, $1;                                                                                                                                    
        my $after  = substr $json, $1;                                                                                                                                       
        print color 'red';                                                                                                                                                   
        print $_;                                                                                                                                                            
        print color 'reset';                                                                                                                                                 
        print "Error is at end of this JSON:\n";                                                                                                                             
        print color 'white';                                                                                                                                                 
        print $before;                                                                                                                                                       
        print color 'red';                                                                                                                                                   
        print $after;                                                                                                                                                        
        print color 'reset';                                                                                                                                                 
        exit;                                                                                                                                                                
    }                                                                                                                                                                        
    else {                                                                                                                                                                   
        die $_;
   }
};                                                                                                                                                                           
my $result = system("curl -XGET $URL --data \@$json_file") == 0                                                                                                  
    or die "Could not query ElasticSearch: $?";                                                                                                                              
print $result;

If I get my JSON formatted poorly I'd have almost useless error messages like this:

malformed JSON string, neither array, object, number, string or atom, at character offset 333 (before "}\n") at /home/cpoe/bin/json_check line 14, <$fh> line 1.

That's when it occurred to me the easy way to fix it. The json_check script finds the offset and prints the first half of the JSON in white and the second half in red. It makes it trivial to spot exactly where the JSON parser thinks the error is.

Of course, the ElasticSearch engine still gives verbose error messages, but this is a step in the right direction. I can now query ElasticSearch directly from vim and it's making my life much easier.

Next, modifying my JSON to allow me to specify which index I want. It's all a nasty hack, but then, Perl is the official programming language of R'lyeh.

1 Comment

I use the debugger to play with ElasticSearch:


perl -de 0

> use ElasticSearch; 
> $e=ElasticSearch->new();

# print all JSON to STDERR
> $e->trace_calls(1); 

# do something
> $e->cluster_health; 

# show all available methods
> m $e 

# print usage for method index()
> $e->index(foo=>1)  

The trace calls method is particularly useful when using ElasticSearch::SearchBuilder, which is a more compact, more Perlish syntax than the standard Query DSL available in ElasticSearch. trace_calls() allows you to see and debug the generated query..

Leave a comment

About Ovid

user-pic Have Perl; Will Travel. Freelance Perl/Testing/Agile consultant. Photo by http://www.circle23.com/. Warning: that site is not safe for work. The photographer is a good friend of mine, though, and it's appropriate to credit his work.