App-ElasticSearch-Utilities

 view release on metacpan or  search on metacpan

MANIFEST  view on Meta::CPAN

scripts/es-nodes.pl
scripts/es-open.pl
scripts/es-search.pl
scripts/es-status.pl
scripts/es-storage-overview.pl
t/00-compile.t
t/01-query.t
t/01-querystring.t
t/02-index-data.t
t/03-hash-flattening.t
t/04-aggregate-expand.t
t/05-aggregate-flatten.t
weaver.ini
xt/author/critic.t
xt/author/eol.t
xt/author/no-tabs.t
xt/author/pod-coverage.t
xt/author/pod-syntax.t

README.mkdn  view on Meta::CPAN


The tools are all wrapped in their own documentation, please see:

    $UTILITY --help
    $UTILITY --manual

For individual options and capabilities

## PATTERNS

Patterns are used to match an index to the aliases it should have.  A few symbols are expanded into
regular expressions.  Those patterns are:

    *       expands to match any number of any characters.
    DATE    expands to match YYYY.MM.DD, YYYY-MM-DD, or YYYYMMDD
    ANY     expands to match any number of any characters.

# CONFIG FILES

Some options may be specified in the **/etc/es-utils.yaml**, **$HOME/.es-utils.yaml**
or **$HOME/.config/es-utils/config.yaml** file:

    ---
    base: logstash
    days: 7
    host: esproxy.example.com

README.mkdn  view on Meta::CPAN

- **days**

    How many days backwards you want your operation to be relevant.

- **datesep**

    Default is '.' Can be set to an empty string for no separator.

- **pattern**

    A pattern to match the indexes.  Can expand the following key words and characters:

        '*'    expanded to '.*'
        'ANY'  expanded to '.*'
        'DATE' expanded to a pattern to match a date,

    The indexes are compared against this pattern.

# OVERVIEW

In addition to the scripts, the libraries provide a simplistic interface to
write your own scripts. It builds `CLI::Helpers` to provide consistent options
for scripts.

    use App::ElasticSearch::Utilities qw(:all);

examples/es-parse-query-string.pl  view on Meta::CPAN

if( $OPT{field} ) {
    foreach my $f ( keys %{ $OPT{field} } ) {
        $fields{$f} = { type => $OPT{field}->{$f} },
    }
    output({color=>'yellow'}, "Fields: " . $json->encode(\%fields));
}
my $qs    = App::ElasticSearch::Utilities::QueryString->new(
                fields_meta => \%fields,
                default_join => $OPT{or} ? 'OR' : 'AND',
);
my $query = $qs->expand_query_string(@ARGV);

output({color=>'cyan'}, "Request URI Params:");
output($json->encode($query->uri_params));

output({clear=>1,color=>'yellow'}, "Request Body:");
output($json->encode($query->request_body));

lib/App/ElasticSearch/Utilities.pm  view on Meta::CPAN


The tools are all wrapped in their own documentation, please see:

    $UTILITY --help
    $UTILITY --manual

For individual options and capabilities

=head2 PATTERNS

Patterns are used to match an index to the aliases it should have.  A few symbols are expanded into
regular expressions.  Those patterns are:

    *       expands to match any number of any characters.
    DATE    expands to match YYYY.MM.DD, YYYY-MM-DD, or YYYYMMDD
    ANY     expands to match any number of any characters.

=head1 CONFIG FILES

Some options may be specified in the B</etc/es-utils.yaml>, B<$HOME/.es-utils.yaml>
or B<$HOME/.config/es-utils/config.yaml> file:

    ---
    base: logstash
    days: 7
    host: esproxy.example.com

lib/App/ElasticSearch/Utilities.pm  view on Meta::CPAN

=item B<days>

How many days backwards you want your operation to be relevant.

=item B<datesep>

Default is '.' Can be set to an empty string for no separator.

=item B<pattern>

A pattern to match the indexes.  Can expand the following key words and characters:

    '*'    expanded to '.*'
    'ANY'  expanded to '.*'
    'DATE' expanded to a pattern to match a date,

The indexes are compared against this pattern.

=back

=head1 OVERVIEW

In addition to the scripts, the libraries provide a simplistic interface to
write your own scripts. It builds C<CLI::Helpers> to provide consistent options
for scripts.

lib/App/ElasticSearch/Utilities/Aggregations.pm  view on Meta::CPAN

# ABSTRACT: Code to simplify creating and working with Elasticsearch aggregations

use v5.16;
use warnings;

use App::ElasticSearch::Utilities qw(es_format_numeric);

use Storable qw(dclone);
use Sub::Exporter -setup => {
    exports => [ qw(
        expand_aggregate_string
        es_flatten_aggregations es_flatten_aggs
        is_single_stat
    )],
    groups => {
        default => [qw(
            expand_aggregate_string
            es_flatten_aggregations es_flatten_aggs
            is_single_stat
        )],
    },
};

my %Aggregations;


$Aggregations{terms} = {

lib/App/ElasticSearch/Utilities/Aggregations.pm  view on Meta::CPAN


sub is_single_stat {
    my ($agg) = @_;
    return unless $agg;
    return unless exists $Aggregations{$agg};
    return unless exists $Aggregations{$agg}->{single_stat};
    return $Aggregations{$agg}->{single_stat};
}


sub expand_aggregate_string {
    my ($token) = @_;

    my %aggs = ();
    foreach my $def ( split /\+/, $token ) {
        my $alias = $def =~ s/^(\w+)=// ? $1 : undef;
        my @parts = split /:/, $def, 3;
        if( @parts == 1 ) {
            $alias ||= $def;
            $aggs{$alias} = { terms => { field => $def, size => 20 } };
            next;

lib/App/ElasticSearch/Utilities/Aggregations.pm  view on Meta::CPAN

=head1 VERSION

version 8.9

=head1 FUNCTIONS

=head2 is_single_stat()

Returns true if an aggregation returns a single value.

=head2 expand_aggregate_string( token )

Takes a simplified aggregation grammar and expands it the full aggregation hash.

Simple Terms:

    field_name

To

    {
        field_name => {
            terms => {

lib/App/ElasticSearch/Utilities/Query.pm  view on Meta::CPAN

    $self->set_aggregations(\%wrapper);
}


sub aggregations_by {
    my ($self,$dir,$aggs) = @_;

    my @sort = ();
    my %aggs = ();
    foreach my $def (@{ $aggs }) {
        my ($name,$agg) = %{ expand_aggregate_string($def) };
        next unless is_single_stat(keys %{ $agg });
        $aggs{$name} = $agg;
        push @sort, { $name => $dir };
    }
    if( @sort ) {
        push @sort, { '_count' => 'desc' };

        my $ref_aggs = $self->aggregations;
        foreach my $name ( keys %{ $ref_aggs } ) {
            foreach my $k ( keys %{ $ref_aggs->{$name} } ) {

lib/App/ElasticSearch/Utilities/Query.pm  view on Meta::CPAN

            }
        }
    }

=head2 aggregations_by( [asc | desc] => aggregation_string )

Applies a sort to all aggregations at the current level based on the
aggregation string.

Aggregation strings are parsed with the
L<App::ElasticSearch::Utilities::Aggregations> C<expand_aggregate_string()>
functions.

Examples:

    $q->aggregations_by( desc => [ qw( sum:bytes ) ] );
    $q->aggregations_by( desc => [ qw( sum:bytes cardinality:user_agent ) ] );

=head2 set_scan_scroll($ctxt_life)

This function emulates the old scan scroll feature in early version of Elasticsearch. It takes

lib/App/ElasticSearch/Utilities/QueryString.pm  view on Meta::CPAN

);


has fields_meta => (
    is => 'rw',
    isa => HashRef,
    default => sub { {} },
);


sub expand_query_string {
    my $self = shift;

    my $query  = App::ElasticSearch::Utilities::Query->new(
        fields_meta => $self->fields_meta,
    );
    my @processed = ();
    TOKEN: foreach my $token (@_) {
        foreach my $p (@{ $self->plugins }) {
            my $res = $p->handle_token($token);
            if( defined $res ) {

lib/App/ElasticSearch/Utilities/QueryString.pm  view on Meta::CPAN

=head1 NAME

App::ElasticSearch::Utilities::QueryString - CLI query string fixer

=head1 VERSION

version 8.9

=head1 SYNOPSIS

This class provides a pluggable architecture to expand query strings on the
command-line into complex Elasticsearch queries.

=head1 ATTRIBUTES

=head2 context

Defaults to 'query', but can also be set to 'filter' so the elements will be
added to the 'must' or 'filter' parameter.

=head2 search_path

lib/App/ElasticSearch/Utilities/QueryString.pm  view on Meta::CPAN

=head2 plugins

Array reference of ordered query string processing plugins, lazily assembled.

=head2 fields_meta

A hash reference with the field data from L<App::ElasticSearch::Utilities::es_index_fields>.

=head1 METHODS

=head2 expand_query_string(@tokens)

This function takes a list of tokens, often from the command line via @ARGV.  Uses
a plugin infrastructure to allow customization.

Returns: L<App::ElasticSearch::Utilities::Query> object

=head1 TOKENS

The token expansion plugins can return undefined, which is basically a noop on the token.
The plugin can return a hash reference, which marks that token as handled and no other plugins

lib/App/ElasticSearch/Utilities/QueryString.pm  view on Meta::CPAN


    # message field is text
    message:"foo"

Is translated into:

    { match => { message => "foo" } }

=head2 App::ElasticSearch::Utilities::QueryString::IP

If a field is an IP address uses CIDR Notation, it's expanded to a range query.

    src_ip:10.0/8 => src_ip:[10.0.0.0 TO 10.255.255.255]

=head2 App::ElasticSearch::Utilities::QueryString::Ranges

This plugin translates some special comparison operators so you don't need to
remember them anymore.

Example:

lib/App/ElasticSearch/Utilities/QueryString.pm  view on Meta::CPAN

JSON source file with:

    { "first": { "second": { "third": [ "bob", "alice" ] } } }
    { "first": { "second": { "third": "ginger" } } }
    { "first": { "second": { "nope":  "fred" } } }

We could search using:

    actor:test.json[first.second.third]

Which would expand to:

    { "terms": { "actor": [ "alice", "bob", "ginger" ] } }

This option will iterate through the whole file and unique the elements of the list.  They will then be transformed into
an appropriate L<terms query|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-terms-query.html>.

=head3 Wildcards

We can also have a group of wildcard or regexp in a file:

    $ cat wildcards.dat
    *@gmail.com
    *@yahoo.com

To enable wildcard parsing, prefix the filename with a C<*>.

    es-search.pl to_address:*wildcards.dat

Which expands the query to:

    {
      "bool": {
        "minimum_should_match":1,
        "should": [
           {"wildcard":{"to_outbound":{"value":"*@gmail.com"}}},
           {"wildcard":{"to_outbound":{"value":"*@yahoo.com"}}}
        ]
      }
    }

lib/App/ElasticSearch/Utilities/QueryString.pm  view on Meta::CPAN

If you'd like to specify a file full of regexp, you can do that as well:

    $ cat regexp.dat
    .*google\.com$
    .*yahoo\.com$

To enable regexp parsing, prefix the filename with a C<~>.

    es-search.pl to_address:~regexp.dat

Which expands the query to:

    {
      "bool": {
        "minimum_should_match":1,
        "should": [
          {"regexp":{"to_outbound":{"value":".*google\\.com$"}}},
          {"regexp":{"to_outbound":{"value":".*yahoo\\.com$"}}}
        ]
      }
    }

lib/App/ElasticSearch/Utilities/QueryString/FileExpansion.pm  view on Meta::CPAN

JSON source file with:

    { "first": { "second": { "third": [ "bob", "alice" ] } } }
    { "first": { "second": { "third": "ginger" } } }
    { "first": { "second": { "nope":  "fred" } } }

We could search using:

    actor:test.json[first.second.third]

Which would expand to:

    { "terms": { "actor": [ "alice", "bob", "ginger" ] } }

This option will iterate through the whole file and unique the elements of the list.  They will then be transformed into
an appropriate L<terms query|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-terms-query.html>.

=head3 Wildcards

We can also have a group of wildcard or regexp in a file:

    $ cat wildcards.dat
    *@gmail.com
    *@yahoo.com

To enable wildcard parsing, prefix the filename with a C<*>.

    es-search.pl to_address:*wildcards.dat

Which expands the query to:

    {
      "bool": {
        "minimum_should_match":1,
        "should": [
           {"wildcard":{"to_outbound":{"value":"*@gmail.com"}}},
           {"wildcard":{"to_outbound":{"value":"*@yahoo.com"}}}
        ]
      }
    }

lib/App/ElasticSearch/Utilities/QueryString/FileExpansion.pm  view on Meta::CPAN

If you'd like to specify a file full of regexp, you can do that as well:

    $ cat regexp.dat
    .*google\.com$
    .*yahoo\.com$

To enable regexp parsing, prefix the filename with a C<~>.

    es-search.pl to_address:~regexp.dat

Which expands the query to:

    {
      "bool": {
        "minimum_should_match":1,
        "should": [
          {"regexp":{"to_outbound":{"value":".*google\\.com$"}}},
          {"regexp":{"to_outbound":{"value":".*yahoo\\.com$"}}}
        ]
      }
    }

lib/App/ElasticSearch/Utilities/QueryString/IP.pm  view on Meta::CPAN

App::ElasticSearch::Utilities::QueryString::IP - Expand IP CIDR Notation to ES ranges

=head1 VERSION

version 8.9

=head1 SYNOPSIS

=head2 App::ElasticSearch::Utilities::QueryString::IP

If a field is an IP address uses CIDR Notation, it's expanded to a range query.

    src_ip:10.0/8 => src_ip:[10.0.0.0 TO 10.255.255.255]

=for Pod::Coverage handle_token

=head1 AUTHOR

Brad Lhotsky <brad@divisionbyzero.net>

=head1 COPYRIGHT AND LICENSE

lib/App/ElasticSearch/Utilities/QueryString/Nested.pm  view on Meta::CPAN

use namespace::autoclean;

use Moo;
with 'App::ElasticSearch::Utilities::QueryString::Plugin';


has 'qs' => (
    is       => 'ro',
    init_arg => undef,
    default  => sub { App::ElasticSearch::Utilities::QueryString->new() },
    handles  => [qw(expand_query_string)],
);

my %Reserved = map { $_ => 1 } qw( _prefix_ _exists_ _missing_ );


sub handle_token {
    my ($self,$token) = @_;
    debug(sprintf "%s - evaluating token '%s'", $self->name, $token);

    # split on spaces

lib/App/ElasticSearch/Utilities/QueryString/Nested.pm  view on Meta::CPAN

    return unless $remainder;

    # If we're nested theres a second colon in there somewhere
    if( $remainder =~ /^[\w\.]+:.+/ ) {
        if( $remainder =~ /^[0-9a-fA-F]{2}(?::[0-9a-fA-F]{2}){2,5}/ ) {
            # This is a mac address, skip it
            return;
        }
        $subtokens[-1] =~ s/"$// if @subtokens;
        debug(sprintf "%s - Found nested query, path is %s, remainder: %s", $self->name, $path,$remainder);
        my $q = $self->expand_query_string($remainder,@subtokens);
        debug_var($q->query);
        return [{ nested => {query => $q->query, path => $path}}];
    }
    return;
}

# Return True;
1;

__END__

scripts/es-aggregate.pl  view on Meta::CPAN

    ['manual', "Display complete options and documentation.", { shortcircuit => 1 }],
);
if( $opt->help ) {
    print $usage->text;
    exit 0;
}
pod2usage(-exitval => 0, -verbose => 2) if $opt->manual;

my $json = JSON->new->utf8->canonical;
my $qs = App::ElasticSearch::Utilities::QueryString->new();
my $q  = $qs->expand_query_string( @ARGV );
$q->set_size(0);

# Figure out where the --by's are spatially
my $ORDER     = $opt->asc ? 'asc' : 'desc';
my @agg_param = @{ $opt->aggregate };
my @by_param  = $opt->by ? @{ $opt->by } : ();
my @by        = ();

foreach my $token ( reverse @args ) {
    if( $token =~ /^--agg/ ) {
        $q->wrap_aggs( %{ expand_aggregate_string( pop @agg_param ) } );
        $q->aggs_by( $ORDER => [@by] ) if @by;
        @by=();
    }
    elsif( $token eq '--by' ) {
        push @by, pop @by_param;
    }
}

output({color=>'yellow'}, YAML::XS::Dump($q->aggregations)) if $opt->show_aggs;

scripts/es-alias-manager.pl  view on Meta::CPAN

        |- iad-logstash-2013.07.18
        |- nyc-logstash-2013.07.18
        `- ams-logstash-2013.07.18

This lets you use index templates and the index.routing.allocation to isolate data by datacenter or another
parameter to certain nodes while allowing all the nodes to work together as cleanly as possible.  This also facilitates
the default expectations of Kibana to have a single index per day when you may need more.

=head2 PATTERN VARIABLES

Patterns are used to match an index to the aliases it should have.  A few symbols are expanded into
regular expressions.  Those patterns are:

    The '*' expands to match any number of any characters.
    The '?' expands to match any single character.
    {{DATE}} expands to match YYYY.MM.DD, YYYY-MM-DD, or YYYYMMDD

=head2 ALIAS VARIABLES

For daily indices, the following variables are available:

    {{DATE}} - Expands to YYYY.MM.DD for the current day of the current index

For relative period indices, the following variable is B<required>.

    {{PERIOD}} - Name of the period

scripts/es-copy-index.pl  view on Meta::CPAN

    output({color=>'red',IMPORTANT=>1},
        "FATAL: Cannot copy from the same host to the same index name!"
    );
    exit 1;
}

#------------------------------------------------------------------------#
# Build the Query
my $JSON = JSON->new->pretty->canonical;
my $qs = App::ElasticSearch::Utilities::QueryString->new();
my $q  = @ARGV ? $qs->expand_query_string(@ARGV)
               : App::ElasticSearch::Utilities::Query->new(must => {match_all=>{}});

$q->set_scan_scroll('1m');
$q->set_size( $INDEX{block} );

# Connect to ElasticSearch
my %ES = ();
foreach my $dir (qw(from to)) {
    $ES{$dir} = es_connect( $HOST{$dir} );
}

scripts/es-copy-index.pl  view on Meta::CPAN


    # message field is text
    message:"foo"

Is translated into:

    { match => { message => "foo" } }

=head2 App::ElasticSearch::Utilities::QueryString::IP

If a field is an IP address uses CIDR Notation, it's expanded to a range query.

    src_ip:10.0/8 => src_ip:[10.0.0.0 TO 10.255.255.255]

=head2 App::ElasticSearch::Utilities::QueryString::Ranges

This plugin translates some special comparison operators so you don't need to
remember them anymore.

Example:

scripts/es-copy-index.pl  view on Meta::CPAN

JSON source file with:

    { "first": { "second": { "third": [ "bob", "alice" ] } } }
    { "first": { "second": { "third": "ginger" } } }
    { "first": { "second": { "nope":  "fred" } } }

We could search using:

    actor:test.json[first.second.third]

Which would expand to:

    { "terms": { "actor": [ "alice", "bob", "ginger" ] } }

This option will iterate through the whole file and unique the elements of the list.  They will then be transformed into
an appropriate L<terms query|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-terms-query.html>.

=head3 Wildcards

We can also have a group of wildcard or regexp in a file:

    $ cat wildcards.dat
    *@gmail.com
    *@yahoo.com

To enable wildcard parsing, prefix the filename with a C<*>.

    es-search.pl to_address:*wildcards.dat

Which expands the query to:

    {
      "bool": {
        "minimum_should_match":1,
        "should": [
           {"wildcard":{"to_outbound":{"value":"*@gmail.com"}}},
           {"wildcard":{"to_outbound":{"value":"*@yahoo.com"}}}
        ]
      }
    }

scripts/es-copy-index.pl  view on Meta::CPAN

If you'd like to specify a file full of regexp, you can do that as well:

    $ cat regexp.dat
    .*google\.com$
    .*yahoo\.com$

To enable regexp parsing, prefix the filename with a C<~>.

    es-search.pl to_address:~regexp.dat

Which expands the query to:

    {
      "bool": {
        "minimum_should_match":1,
        "should": [
          {"regexp":{"to_outbound":{"value":".*google\\.com$"}}},
          {"regexp":{"to_outbound":{"value":".*yahoo\\.com$"}}}
        ]
      }
    }

scripts/es-search.pl  view on Meta::CPAN

));

# Search string is the rest of the argument string
my $context = $OPT{filter} ? 'filter' : 'must';
my $qs = App::ElasticSearch::Utilities::QueryString->new(
            $OPT{filter} ?  (context => 'filter') : (),
            default_join => $OPT{or} ? 'OR' : 'AND',
);
my $q = exists $OPT{'match-all'} && $OPT{'match-all'}
            ? App::ElasticSearch::Utilities::Query->new($context => { match_all => {} })
            : $qs->expand_query_string(@ARGV);

$q->set_timeout('10s');
$q->set_scroll('30s');

if( exists $OPT{prefix} ){
    foreach my $prefix (@{ $OPT{prefix} }) {
        my ($f,$v) = split /:/, $prefix, 2;
        next unless $f && $v;
        $q->add_bool( $context => { prefix => { $f => $v } } );
    }

scripts/es-search.pl  view on Meta::CPAN


    my %params = ();
    $params{missing} = 'MISSING' if $OPT{'with-missing'} and $top_agg eq 'terms';

    my $field = shift @agg_fields;
    $agg_header = "count\tpct\t" . $field;
    $agg{$top_agg} = { field => $field, %params };

    if( $OPT{'bg-filter'} && $top_agg eq 'significant_terms' ) {
        my $bgf = App::ElasticSearch::Utilities::QueryString->new();
        my $bgq = $bgf->expand_query_string($OPT{'bg-filter'});
        $agg{$top_agg}->{background_filter} = $bgq->query;

    }

    if( exists $sub_agg{by} ) {
        $agg_header = "$OPT{by}\t" . $agg_header;
        $agg{$top_agg}->{order} = [ { by => $ORDER }, { "_count" => "desc" } ];
    }
    $agg{aggregations} = \%sub_agg if keys %sub_agg;

scripts/es-search.pl  view on Meta::CPAN

    $ es-search.pl --base logstash error --top program --size 2 --by cardinality:host --with host:5

This will show the top 2 programs with log messages containing the word error by the cardinality (count
distinct host) of hosts showing the top 5 hosts

Without the --with, the results might look like this:

    112314 0.151 sshd
    21224  0.151 ntp

The B<--with> option would expand that output to look like this:

    112314   0.151 host   bastion-804   12431  0.111 sshd
    112314   0.151 host   bastion-803   10009  0.089 sshd
    112314   0.151 host   bastion-805   9768   0.087 sshd
    112314   0.151 host   bastion-801   8789   0.078 sshd
    112314   0.151 host   bastion-802   4121   0.037 sshd
    21224    0.016 host   webapp-324    21223  0.999 ntp
    21224    0.016 host   mail-42       1      0.000 ntp

This may be specified multiple times, the result is more I<rows>, not more I<columns>, e.g.

scripts/es-search.pl  view on Meta::CPAN

=item B<index>

Search only this index for data, may also be a comma separated list

=item B<days>

The number of days back to search, the default is 5

=item B<base>

Index base name, will be expanded using the days back parameter.  The default
is 'logstash' which will expand to 'logstash-YYYY.MM.DD'

=item B<timestamp>

The field in your documents that we'll treat as a "date" type in our queries.

May also be specified in the C<~/.es-utils.yaml> file per index, or index base:

    ---
    host: es-readonly-01
    port: 9200

scripts/es-search.pl  view on Meta::CPAN


    # message field is text
    message:"foo"

Is translated into:

    { match => { message => "foo" } }

=head2 App::ElasticSearch::Utilities::QueryString::IP

If a field is an IP address uses CIDR Notation, it's expanded to a range query.

    src_ip:10.0/8 => src_ip:[10.0.0.0 TO 10.255.255.255]

=head2 App::ElasticSearch::Utilities::QueryString::Ranges

This plugin translates some special comparison operators so you don't need to
remember them anymore.

Example:

scripts/es-search.pl  view on Meta::CPAN

JSON source file with:

    { "first": { "second": { "third": [ "bob", "alice" ] } } }
    { "first": { "second": { "third": "ginger" } } }
    { "first": { "second": { "nope":  "fred" } } }

We could search using:

    actor:test.json[first.second.third]

Which would expand to:

    { "terms": { "actor": [ "alice", "bob", "ginger" ] } }

This option will iterate through the whole file and unique the elements of the list.  They will then be transformed into
an appropriate L<terms query|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-terms-query.html>.

=head3 Wildcards

We can also have a group of wildcard or regexp in a file:

    $ cat wildcards.dat
    *@gmail.com
    *@yahoo.com

To enable wildcard parsing, prefix the filename with a C<*>.

    es-search.pl to_address:*wildcards.dat

Which expands the query to:

    {
      "bool": {
        "minimum_should_match":1,
        "should": [
           {"wildcard":{"to_outbound":{"value":"*@gmail.com"}}},
           {"wildcard":{"to_outbound":{"value":"*@yahoo.com"}}}
        ]
      }
    }

scripts/es-search.pl  view on Meta::CPAN

If you'd like to specify a file full of regexp, you can do that as well:

    $ cat regexp.dat
    .*google\.com$
    .*yahoo\.com$

To enable regexp parsing, prefix the filename with a C<~>.

    es-search.pl to_address:~regexp.dat

Which expands the query to:

    {
      "bool": {
        "minimum_should_match":1,
        "should": [
          {"regexp":{"to_outbound":{"value":".*google\\.com$"}}},
          {"regexp":{"to_outbound":{"value":".*yahoo\\.com$"}}}
        ]
      }
    }

scripts/es-status.pl  view on Meta::CPAN

    my $colorize = sub {
        my ($v) = shift;
        return "green" if $v eq 'false';
        return "yellow" if $v eq 'not set';
        return "red";
    };

    foreach my $index (sort keys %{ $stats } ) {
        my %settings = %{ $stats->{$index}{settings} };
        output({color=>'cyan'}, "$index:");
        my $value = exists $settings{'index.auto_expand_replicas'} && defined $settings{'index.auto_expand_replicas'} ? $settings{'index.auto_expand_replicas'} : 'not set';
        my $color = $colorize->($value);
        output({indent=>1,kv=>1,color=>$color}, "auto_expand_replicas", $value);
        verbose({indent=>1,kv=>1}, "replicas", $settings{'index.number_of_replicas'});
        verbose({indent=>1,kv=>1}, "shards", $settings{'index.number_of_shards'});
    }
}

__END__

=pod

=head1 NAME

t/01-querystring.t  view on Meta::CPAN

    ],
);

my $qs = App::ElasticSearch::Utilities::QueryString->new(
    fields_meta => {
        a_text_field => { type => "text" },
    },
);

foreach my $t (sort keys %tests) {
    my $q = $qs->expand_query_string( @{ $tests{$t}->[0] } );

    is_deeply( $q->query, $tests{$t}->[1], $t )
        or diag( join(' ', @{ $tests{$t}->[0] }) . "\n", Dumper $q->query );
}
done_testing();
__DATA__
alice   50      1.2.3.4
bob     20      1.2.3.5
charlie 70      1.2.3.6

t/04-aggregate-expand.t  view on Meta::CPAN

                terms => {
                    field => 'src_ip',
                    size => 16,
                }
            }
        },
    ],
);

foreach my $t (sort keys %tests) {
    my $agg = expand_aggregate_string( $tests{$t}->[0] );

    is_deeply( $agg, $tests{$t}->[1], $t )
        or diag( Dumper $agg );
}
done_testing();

xt/author/eol.t  view on Meta::CPAN

    'scripts/es-nodes.pl',
    'scripts/es-open.pl',
    'scripts/es-search.pl',
    'scripts/es-status.pl',
    'scripts/es-storage-overview.pl',
    't/00-compile.t',
    't/01-query.t',
    't/01-querystring.t',
    't/02-index-data.t',
    't/03-hash-flattening.t',
    't/04-aggregate-expand.t',
    't/05-aggregate-flatten.t'
);

eol_unix_ok($_, { trailing_whitespace => 1 }) foreach @files;
done_testing;

xt/author/no-tabs.t  view on Meta::CPAN

    'scripts/es-nodes.pl',
    'scripts/es-open.pl',
    'scripts/es-search.pl',
    'scripts/es-status.pl',
    'scripts/es-storage-overview.pl',
    't/00-compile.t',
    't/01-query.t',
    't/01-querystring.t',
    't/02-index-data.t',
    't/03-hash-flattening.t',
    't/04-aggregate-expand.t',
    't/05-aggregate-flatten.t'
);

notabs_ok($_) foreach @files;
done_testing;



( run in 1.057 second using v1.01-cache-2.11-cpan-5623c5533a1 )