Perlish concise query syntax for ElasticSearch

Announcing ElasticSearch::SearchBuilder

In Perl, we like to put important things first, so the ElasticSearch query language has always felt a bit wrong to me. For instance, to find docs where the content field contains the text keywords:

    # op        field       value
    { text => { content => 'keywords' } }

To me, the important part of this is the field that we’re operating on, so this feels more natural:

    # field        op       value
    { content => { text => 'keywords' }}

So, in the spirit of SQL::Abstract I am proud to announce ElasticSearch::SearchBuilder, which is tightly integrated into the latest ElasticSearch.pm version 0.38.

Any method which takes a query or filter param (eg search() now also accepts a queryb or filterb parameter instead, whose value will be parsed via SearchBuilder:

Do a full text search of the _all field for 'my keywords':

    $es->search( queryb=> 'my keywords' );

Find docs whose title field contains the text apple but not orange, whose status field contains the value active:

$es->search(
    queryb => {
        title => {
            '='  => 'apple',
            '!=' => 'orange'
        },
        -filter => {
            status => 'active'
        }
    }
)

If you have suggestions to improve the API or the documentation, please get in touch.

You can try out ElasticSearch::SearchBuilder here.

And finally, a more complex example, to demonstrate how much more concisely you can write queries:

Out of all docs published in 2010 and tagged with either “perl” or “ruby”, find those whose title field contains”my keywords”, in which case consider this doc to be particularly relevant (boost: 2) or the title field is missing but the body field contains 'my keywords':

$es->search(
    queryb => {
        -or => [
            {
                title => {
                    '=' => {
                        query => 'my keywords',
                        boost => 2
                }}
            },
            {
                body    => 'my_keywords',
                -filter => {
                    -missing => 'title'
                }
            },
        ],
        -filter => {
            tags => [ 'perl','ruby' ],
            date => {
                '>=' => '2010-01-01',
                '<'  => '2011-01-01'
            },
        }
    }
)

is the equivalent of:

    $es->search(
        query => {
            filtered => {
                filter => {
                    and => [
                        { 
                            terms => { 
                                tags => ["perl", "ruby"] 
                            } 
                        },
                        { 
                            numericrange => { 
                                date => { 
                                    gte => "2010-01-01", 
                                    lt => "2011-01-01" 
                                }
                            }
                        }
                    ],
                },
                query  => {
                    bool => {
                        should => [
                            { 
                                text => { 
                                    title => { 
                                        boost => 2, 
                                        query => "my keywords" 
                                    } 
                                } 
                            },
                            { 
                                filtered => {
                                    filter => { 
                                        missing => { 
                                            field => "title" 
                                        } 
                                    },
                                    query  => { 
                                        text => { 
                                            body => "mykeywords" 
                                        } 
                                    },
                                }
                            }
                        ],
                    }
                }
            }
        }
    )

Which looks better to you?

4 Comments

Woot. ClintonGormley++

This is very exciting. Dealing with the query DSL was definitely the least fun about taking an app using ES from prototype to production.

If I specify say "-filter => { }" will it know that I just meant no filter?

One example from the documentation that felt wrong:

{ foo => ['-and','bar','baz']}

would maybe be nicer as

{ foo => ['-and' => [ 'bar','baz'] ]}

Leave a comment

About Clinton Gormley

user-pic The doctor will see you now...