Search-Elasticsearch-7.715/0000775000175000017500000000000014133761217015041 5ustar enricoenricoSearch-Elasticsearch-7.715/lib/0000775000175000017500000000000014133761217015607 5ustar enricoenricoSearch-Elasticsearch-7.715/lib/Search/0000775000175000017500000000000014133761217017014 5ustar enricoenricoSearch-Elasticsearch-7.715/lib/Search/Elasticsearch.pm0000644000175000017500000003543214133761217022131 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch; use Moo 2.001000 (); use Search::Elasticsearch::Util qw(parse_params load_plugin); use namespace::clean; our $VERSION = '7.715'; my %Default_Plugins = ( client => [ 'Search::Elasticsearch::Client', '7_0::Direct' ], cxn_factory => [ 'Search::Elasticsearch::Cxn::Factory', '' ], cxn_pool => [ 'Search::Elasticsearch::CxnPool', 'Static' ], logger => [ 'Search::Elasticsearch::Logger', 'LogAny' ], serializer => [ 'Search::Elasticsearch::Serializer', 'JSON' ], transport => [ 'Search::Elasticsearch::Transport', '' ], ); my @Load_Order = qw( serializer logger cxn_factory cxn_pool transport client ); #=================================== sub new { #=================================== my ( $class, $params ) = parse_params(@_); $params->{cxn} ||= 'HTTPTiny'; my $plugins = delete $params->{plugins} || []; $plugins = [$plugins] unless ref $plugins eq 'ARRAY'; for my $name (@Load_Order) { my ( $base, $default ) = @{ $Default_Plugins{$name} }; my $sub_class = $params->{$name} || $default; my $plugin_class = load_plugin( $base, $sub_class ); $params->{$name} = $plugin_class->new($params); } for my $name (@$plugins) { my $plugin_class = load_plugin( 'Search::Elasticsearch::Plugin', $name ); $plugin_class->_init_plugin($params); } return $params->{client}; } 1; =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch - The official client for Elasticsearch =head1 VERSION version 7.715 =head1 SYNOPSIS use Search::Elasticsearch; # Connect to localhost:9200: my $e = Search::Elasticsearch->new(); # Round-robin between two nodes: my $e = Search::Elasticsearch->new( nodes => [ 'search1:9200', 'search2:9200' ] ); # Connect to cluster at search1:9200, sniff all nodes and round-robin between them: my $e = Search::Elasticsearch->new( nodes => 'search1:9200', cxn_pool => 'Sniff' ); # Index a document: $e->index( index => 'my_app', type => 'blog_post', id => 1, body => { title => 'Elasticsearch clients', content => 'Interesting content...', date => '2013-09-24' } ); # Get the document: my $doc = $e->get( index => 'my_app', type => 'blog_post', id => 1 ); # Search: my $results = $e->search( index => 'my_app', body => { query => { match => { title => 'elasticsearch' } } } ); # Cluster requests: $info = $e->cluster->info; $health = $e->cluster->health; $node_stats = $e->cluster->node_stats; # Index requests: $e->indices->create(index=>'my_index'); $e->indices->delete(index=>'my_index'); =head1 DESCRIPTION L is the official Perl client for Elasticsearch, supported by L. Elasticsearch itself is a flexible and powerful open source, distributed real-time search and analytics engine for the cloud. You can read more about it on L. =head1 PREVIOUS VERSIONS OF ELASTICSEARCH This version of the client supports the Elasticsearch 7.0 branch, which is not backwards compatible with earlier branches. If you need to talk to a version of Elasticsearch before 7.0.0, please install one of the following packages: =over =item * L =item * L =item * L =back =head2 Motivation =over I Leonardo da Vinci =back All of us have opinions, especially when it comes to designing APIs. Unfortunately, the opinions of programmers seldom coincide. The intention of this client, and of the officially supported clients available for other languages, is to provide robust support for the full native Elasticsearch API with as few opinions as possible: you should be able to read the L and understand how to use this client, or any of the other official clients. Should you decide that you want to customize the API, then this client provides the basis for your code. It does the hard stuff for you, allowing you to build on top of it. =head2 Features This client provides: =over =item * Full support for all Elasticsearch APIs =item * HTTP backend (for an async backend using L, see L) =item * Robust networking support which handles load balancing, failure detection and failover =item * Good defaults =item * Helper utilities for more complex operations, such as L, and L =item * Logging support via L =item * Compatibility with the official clients for Python, Ruby, PHP, and Javascript =item * Easy extensibility =back =head1 INSTALLING ELASTICSEARCH You can download the latest version of Elasticsearch from L. See the L for details. You will need to have a recent version of Java installed, preferably the Java v8 from Sun. =head1 CREATING A NEW INSTANCE The L method returns a new L which can be used to run requests against the Elasticsearch cluster. use Search::Elasticsearch; my $e = Search::Elasticsearch->new( %params ); The most important arguments to L are the following: =head2 C The C parameter tells the client which Elasticsearch nodes it should talk to. It can be a single node, multiples nodes or, if not specified, will default to C: # default: localhost:9200 $e = Search::Elasticsearch->new(); # single $e = Search::Elasticsearch->new( nodes => 'search_1:9200'); # multiple $e = Search::Elasticsearch->new( nodes => [ 'search_1:9200', 'search_2:9200' ] ); Each C can be a URL including a scheme, host, port, path and userinfo (for authentication). For instance, this would be a valid node: https://username:password@search.domain.com:443/prefix/path See L for more on node specification. =head2 C The L modules manage connections to nodes in the Elasticsearch cluster. They handle the load balancing between nodes and failover when nodes fail. Which C you should use depends on where your cluster is. There are three choices: =over =item * C $e = Search::Elasticsearch->new( cxn_pool => 'Static' # default nodes => [ 'search1.domain.com:9200', 'search2.domain.com:9200' ], ); The L connection pool, which is the default, should be used when you don't have direct access to the Elasticsearch cluster, eg when you are accessing the cluster through a proxy. See L for more. =item * C $e = Search::Elasticsearch->new( cxn_pool => 'Sniff', nodes => [ 'search1:9200', 'search2:9200' ], ); The L connection pool should be used when you B have direct access to the Elasticsearch cluster, eg when your web servers and Elasticsearch servers are on the same network. The nodes that you specify are used to I the cluster, which is then I to find the current list of live nodes that the cluster knows about. See L. =item * C $e = Search::Elasticsearch->new( cxn_pool => 'Static::NoPing' nodes => [ 'proxy1.domain.com:80', 'proxy2.domain.com:80' ], ); The L connection pool should be used when your access to a remote cluster is so limited that you cannot ping individual nodes with a C request. See L for more. =back =head2 C For debugging purposes, it is useful to be able to dump the actual HTTP requests which are sent to the cluster, and the response that is received. This can be enabled with the C parameter, as follows: # To STDERR $e = Search::Elasticsearch->new( trace_to => 'Stderr' ); # To a file $e = Search::Elasticsearch->new( trace_to => ['File','/path/to/filename'] ); Logging is handled by L. See L for more information. =head2 Other Other arguments are explained in the respective L. =head1 RUNNING REQUESTS When you create a new instance of Search::Elasticsearch, it returns a L object, which can be used for running requests. use Search::Elasticsearch; my $e = Search::Elasticsearch->new( %params ); # create an index $e->indices->create( index => 'my_index' ); # index a document $e->index( index => 'my_index', type => 'blog_post', id => 1, body => { title => 'Elasticsearch clients', content => 'Interesting content...', date => '2013-09-24' } ); See L for more details about the requests that can be run. =head1 MODULES Each chunk of functionality is handled by a different module, which can be specified in the call to L as shown in L above. For instance, the following will use the L module for the connection pool. $e = Search::Elasticsearch->new( cxn_pool => 'Sniff' ); Custom modules can be named with the appropriate prefix, eg C, or by prefixing the full class name with C<+>: $e = Search::Elasticsearch->new( cxn_pool => '+My::Custom::CxnClass' ); The modules that you can override are specified with the following arguments to L: =head2 C The class to use for the client functionality, which provides methods that can be called to execute requests, such as C, C or C. The client parses the user's requests and passes them to the L class to be executed. The default version of the client is C<7_0::Direct>, which can be explicitly specified as follows: $e = Search::Elasticsearch->new( client => '7_0::Direct' ); =head2 C The Transport class accepts a parsed request from the L class, fetches a L from its L and tries to execute the request, retrying after failure where appropriate. See: =over =item * L =back =head2 C The class which handles raw requests to Elasticsearch nodes. See: =over =item * L (default) =item * L =item * L =back =head2 C The class which the L uses to create new L objects. See: =over =item * L =back =head2 C (2) The class to use for the L functionality. It calls the L class to create new L objects when appropriate. See: =over =item * L (default) =item * L =item * L =back =head2 C The class to use for logging events and tracing HTTP requests/responses. See: =over =item * L =back =head2 C The class to use for serializing request bodies and deserializing response bodies. See: =over =item * L (default) =item * L =item * L =item * L =back =head1 BUGS This is a stable API but this implementation is new. Watch this space for new releases. If you have any suggestions for improvements, or find any bugs, please report them to L. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. =head1 SUPPORT You can find documentation for this module with the perldoc command. perldoc Search::Elasticsearch You can also look for information at: =over 4 =item * GitHub L =item * CPAN Ratings L =item * Search MetaCPAN L =item * IRC The L<#elasticsearch|irc://irc.freenode.net/elasticsearch> channel on C. =item * Mailing list The main L. =back =head1 TEST SUITE The full test suite requires a live Elasticsearch node to run, and should be run as : perl Makefile.PL ES=localhost:9200 make test B You can change the Cxn class which is used by setting the C environment variable: ES_CXN=NetCurl ES=localhost:9200 make test =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut __END__ # ABSTRACT: The official client for Elasticsearch Search-Elasticsearch-7.715/lib/Search/Elasticsearch/0000775000175000017500000000000014133761217021566 5ustar enricoenricoSearch-Elasticsearch-7.715/lib/Search/Elasticsearch/Error.pm0000644000175000017500000002372114133761217023220 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::Error; $Search::Elasticsearch::Error::VERSION = '7.715'; our $DEBUG = 0; @Search::Elasticsearch::Error::Internal::ISA = __PACKAGE__; @Search::Elasticsearch::Error::Param::ISA = __PACKAGE__; @Search::Elasticsearch::Error::NoNodes::ISA = __PACKAGE__; @Search::Elasticsearch::Error::Unauthorized::ISA = __PACKAGE__; @Search::Elasticsearch::Error::Forbidden::ISA = __PACKAGE__; @Search::Elasticsearch::Error::Illegal::ISA = __PACKAGE__; @Search::Elasticsearch::Error::Request::ISA = __PACKAGE__; @Search::Elasticsearch::Error::Timeout::ISA = __PACKAGE__; @Search::Elasticsearch::Error::Cxn::ISA = __PACKAGE__; @Search::Elasticsearch::Error::Serializer::ISA = __PACKAGE__; @Search::Elasticsearch::Error::Conflict::ISA = ( 'Search::Elasticsearch::Error::Request', __PACKAGE__ ); @Search::Elasticsearch::Error::Missing::ISA = ( 'Search::Elasticsearch::Error::Request', __PACKAGE__ ); @Search::Elasticsearch::Error::RequestTimeout::ISA = ( 'Search::Elasticsearch::Error::Request', __PACKAGE__ ); @Search::Elasticsearch::Error::ContentLength::ISA = ( __PACKAGE__, 'Search::Elasticsearch::Error::Request' ); @Search::Elasticsearch::Error::SSL::ISA = ( __PACKAGE__, 'Search::Elasticsearch::Error::Cxn' ); @Search::Elasticsearch::Error::BadGateway::ISA = ( 'Search::Elasticsearch::Error::Cxn', __PACKAGE__ ); @Search::Elasticsearch::Error::Unavailable::ISA = ( 'Search::Elasticsearch::Error::Cxn', __PACKAGE__ ); @Search::Elasticsearch::Error::GatewayTimeout::ISA = ( 'Search::Elasticsearch::Error::Cxn', __PACKAGE__ ); use overload ( '""' => '_stringify', 'cmp' => '_compare', ); use Data::Dumper(); #=================================== sub new { #=================================== my ( $class, $type, $msg, $vars, $caller ) = @_; return $type if ref $type; $caller ||= 0; my $error_class = 'Search::Elasticsearch::Error::' . $type; $msg = 'Unknown error' unless defined $msg; local $DEBUG = 2 if $type eq 'Internal'; my $stack = $class->_stack; my $self = bless { type => $type, text => $msg, vars => $vars, stack => $stack, }, $error_class; return $self; } #=================================== sub is { #=================================== my $self = shift; for (@_) { return 1 if $self->isa("Search::Elasticsearch::Error::$_"); } return 0; } #=================================== sub _stringify { #=================================== my $self = shift; local $Data::Dumper::Terse = 1; local $Data::Dumper::Indent = !!$DEBUG; unless ( $self->{msg} ) { my $stack = $self->{stack}; my $caller = $stack->[0]; $self->{msg} = sprintf( "[%s] ** %s, called from sub %s at %s line %d.", $self->{type}, $self->{text}, @{$caller}[ 3, 1, 2 ] ); if ( $self->{vars} ) { $self->{msg} .= sprintf( " With vars: %s\n", Data::Dumper::Dumper $self->{vars} ); } if ( @$stack > 1 ) { $self->{msg} .= sprintf( "Stacktrace:\n%s\n", $self->stacktrace($stack) ); } } return $self->{msg}; } #=================================== sub _compare { #=================================== my ( $self, $other, $swap ) = @_; $self .= ''; ( $self, $other ) = ( $other, $self ) if $swap; return $self cmp $other; } #=================================== sub _stack { #=================================== my $self = shift; my $caller = shift() || 2; my @stack; while ( my @caller = caller( ++$caller ) ) { next if $caller[0] eq 'Try::Tiny'; if ( $caller[3] =~ /^(.+)::__ANON__\[(.+):(\d+)\]$/ ) { @caller = ( $1, $2, $3, '(ANON)' ); } elsif ( $caller[1] =~ /^\(eval \d+\)/ ) { $caller[3] = "modified(" . $caller[3] . ")"; } next if $caller[0] =~ /^Search::Elasticsearch/ and ( $DEBUG < 2 or $caller[3] eq 'Try::Tiny::try' ); push @stack, [ @caller[ 0, 1, 2, 3 ] ]; last unless $DEBUG > 1; } return \@stack; } #=================================== sub stacktrace { #=================================== my $self = shift; my $stack = shift || $self->_stack(); my $o = sprintf "%s\n%-4s %-50s %-5s %s\n%s\n", '-' x 80, '#', 'Package', 'Line', 'Sub-routine', '-' x 80; my $i = 1; for (@$stack) { $o .= sprintf "%-4d %-50s %4d %s\n", $i++, @{$_}[ 0, 2, 3 ]; } return $o .= ( '-' x 80 ) . "\n"; } #=================================== sub TO_JSON { #=================================== my $self = shift; return $self->_stringify; } 1; # ABSTRACT: Errors thrown by Search::Elasticsearch __END__ =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Error - Errors thrown by Search::Elasticsearch =head1 VERSION version 7.715 =head1 DESCRIPTION Errors thrown by Search::Elasticsearch are error objects, which can include a stack trace and information to help debug problems. An error object consists of the following: { type => $type, # eg Missing text => 'Error message', vars => {...}, # vars which may help to explain the error stack => [...], # a stack trace } The C<$Search::Elasticsearch::Error::DEBUG> variable can be set to C<1> or C<2> to increase the verbosity of errors. Error objects stringify to a human readable error message when used in text context (for example: C). They also support the C method to support conversion to JSON when L is enabled. =head1 ERROR CLASSES The following error classes are defined: =over =item * C A bad parameter has been passed to a method. =item * C There was some generic error performing your request in Elasticsearch. This error is triggered by HTTP status codes C<400> and C<500>. This class has the following sub-classes: =over =item * C Invalid (or no) username/password provided as C for a password protected service. These errors are triggered by the C<401> HTTP status code. =item * C A resource that you requested was not found. These errors are triggered by the C<404> HTTP status code. =item * C Your request could not be performed because of some conflict. For instance, if you try to delete a document with a particular version number, and the document has already changed, it will throw a C error. If it can, it will include the C in the error vars. This error is triggered by the C<409> HTTP status code. =item * C The request body was longer than the L. =item * C The request took longer than the specified C. Currently only applies to the L request. =back =item * C The request timed out. =item * C There was an error connecting to a node in the cluster. This error indicates node failure and will be retried on another node. This error has the following sub-classes: =over =item * C The current node is unable to handle your request at the moment. Your request will be retried on another node. This error is triggered by the C<503> HTTP status code. =item * C A proxy between the client and Elasticsearch is unable to connect to Elasticsearch. This error is triggered by the C<502> HTTP status code. =item * C A proxy between the client and Elasticsearch is unable to connect to Elasticsearch within its own timeout. This error is triggered by the C<504> HTTP status code. =item * C There was a problem validating the SSL certificate. Not all backends support this error type. =back =item * C Either the cluster was unable to process the request because it is currently blocking, eg there are not enough master nodes to form a cluster, or because the authenticated user is trying to perform an unauthorized action. This error is triggered by the C<403> HTTP status code. =item * C You have attempted to perform an illegal operation. For instance, you attempted to use a Scroll helper in a different process after forking. =item * C There was an error serializing a variable or deserializing a string. =item * C An internal error occurred - please report this as a bug in this module. =back =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut Search-Elasticsearch-7.715/lib/Search/Elasticsearch/CxnPool/0000775000175000017500000000000014133761217023150 5ustar enricoenricoSearch-Elasticsearch-7.715/lib/Search/Elasticsearch/CxnPool/Sniff.pm0000644000175000017500000001602614133761217024556 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::CxnPool::Sniff; $Search::Elasticsearch::CxnPool::Sniff::VERSION = '7.715'; use Moo; with 'Search::Elasticsearch::Role::CxnPool::Sniff', 'Search::Elasticsearch::Role::Is_Sync'; use Search::Elasticsearch::Util qw(throw); use namespace::clean; #=================================== sub next_cxn { #=================================== my ($self) = @_; $self->sniff if $self->next_sniff <= time(); my $cxns = $self->cxns; my $total = @$cxns; while ( 0 < $total-- ) { my $cxn = $cxns->[ $self->next_cxn_num ]; return $cxn if $cxn->is_live; } throw( "NoNodes", "No nodes are available: [" . $self->cxns_seeds_str . ']' ); } #=================================== sub sniff { #=================================== my $self = shift; my $cxns = $self->cxns; my $total = @$cxns; my @skipped; while ( 0 < $total-- ) { my $cxn = $cxns->[ $self->next_cxn_num ]; if ( $cxn->is_dead ) { push @skipped, $cxn; } else { $self->sniff_cxn($cxn) and return; $cxn->mark_dead; } } for my $cxn (@skipped) { $self->sniff_cxn($cxn) and return; } $self->logger->info("No live nodes available. Trying seed nodes."); for my $seed ( @{ $self->seed_nodes } ) { my $cxn = $self->cxn_factory->new_cxn($seed); $self->sniff_cxn($cxn) and return; } } #=================================== sub sniff_cxn { #=================================== my ( $self, $cxn ) = @_; return $self->parse_sniff( $cxn->sniff ); } 1; # ABSTRACT: A CxnPool for connecting to a local cluster with a dynamic node list __END__ =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::CxnPool::Sniff - A CxnPool for connecting to a local cluster with a dynamic node list =head1 VERSION version 7.715 =head1 SYNOPSIS $e = Search::Elasticsearch->new( cxn_pool => 'Sniff', nodes => [ 'search1:9200', 'search2:9200' ], ); =head1 DESCRIPTION The L connection pool should be used when you B have direct access to the Elasticsearch cluster, eg when your web servers and Elasticsearch servers are on the same network. The nodes that you specify are used to I the cluster, which is then I to find the current list of live nodes that the cluster knows about. This sniff process is repeated regularly, or whenever a node fails, to update the list of healthy nodes. So if you add more nodes to your cluster, they will be auto-discovered during a sniff. If all sniffed nodes fail, then it falls back to sniffing the original I nodes that you specified in C. For L, this module will also dynamically detect the C which the nodes in the cluster will accept. This class does L and L. =head1 CONFIGURATION =head2 C The list of nodes to use to discover the cluster. Can accept a single node, multiple nodes, and defaults to C if no C are specified. See L for details of the node specification. =head2 See also =over =item * L =item * L =item * L =back =head2 Inherited configuration From L =over =item * L =item * L =back From L =over =item * L =back =head1 METHODS =head2 C $cxn = $cxn_pool->next_cxn Returns the next available live node (in round robin fashion), or throws a C error if no nodes can be sniffed from the cluster. =head2 C $cxn_pool->schedule_check Forces a sniff before the next Cxn is returned, to updated the list of healthy nodes in the cluster. =head2 C $bool = $cxn_pool->sniff Sniffs the cluster and returns C if the sniff was successful. =head2 Inherited methods From L =over =item * L =item * L =item * L =back From L =over =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =back =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut Search-Elasticsearch-7.715/lib/Search/Elasticsearch/CxnPool/Static.pm0000644000175000017500000001266414133761217024744 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::CxnPool::Static; $Search::Elasticsearch::CxnPool::Static::VERSION = '7.715'; use Moo; with 'Search::Elasticsearch::Role::CxnPool::Static', 'Search::Elasticsearch::Role::Is_Sync'; use Search::Elasticsearch::Util qw(throw); use namespace::clean; #=================================== sub next_cxn { #=================================== my ($self) = @_; my $cxns = $self->cxns; my $total = @$cxns; my $now = time(); my @skipped; while ( $total-- ) { my $cxn = $cxns->[ $self->next_cxn_num ]; return $cxn if $cxn->is_live; if ( $cxn->next_ping < $now ) { return $cxn if $cxn->pings_ok; } else { push @skipped, $cxn; } } for my $cxn (@skipped) { return $cxn if $cxn->pings_ok; } $_->force_ping for @$cxns; throw( "NoNodes", "No nodes are available: [" . $self->cxns_str . ']' ); } 1; =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::CxnPool::Static - A CxnPool for connecting to a remote cluster with a static list of nodes. =head1 VERSION version 7.715 =head1 SYNOPSIS $e = Search::Elasticsearch->new( cxn_pool => 'Static' # default nodes => [ 'search1:9200', 'search2:9200' ], ); =head1 DESCRIPTION The L connection pool, which is the default, should be used when you don't have direct access to the Elasticsearch cluster, eg when you are accessing the cluster through a proxy. It round-robins through the nodes that you specified, and pings each node before it is used for the first time, to ensure that it is responding. If any node fails, then all nodes are pinged before the next request to ensure that they are still alive and responding. Failed nodes will be pinged regularly to check if they have recovered. This class does L and L. =head1 CONFIGURATION =head2 C The list of nodes to use to serve requests. Can accept a single node, multiple nodes, and defaults to C if no C are specified. See L for details of the node specification. =head2 See also =over =item * L =item * L =item * L =item * L =back =head2 Inherited configuration From L =over =item * L =back =head1 METHODS =head2 C $cxn = $cxn_pool->next_cxn Returns the next available live node (in round robin fashion), or throws a C error if no nodes respond to ping requests. =head2 Inherited methods From L =over =item * L =back From L =over =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =back =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut __END__ # ABSTRACT: A CxnPool for connecting to a remote cluster with a static list of nodes. Search-Elasticsearch-7.715/lib/Search/Elasticsearch/CxnPool/Static/0000775000175000017500000000000014133761217024377 5ustar enricoenricoSearch-Elasticsearch-7.715/lib/Search/Elasticsearch/CxnPool/Static/NoPing.pm0000644000175000017500000001304714133761217026132 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::CxnPool::Static::NoPing; $Search::Elasticsearch::CxnPool::Static::NoPing::VERSION = '7.715'; use Moo; with 'Search::Elasticsearch::Role::CxnPool::Static::NoPing', 'Search::Elasticsearch::Role::Is_Sync'; use Search::Elasticsearch::Util qw(throw); use namespace::clean; 1; =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::CxnPool::Static::NoPing - A CxnPool for connecting to a remote cluster without the ability to ping. =head1 VERSION version 7.715 =head1 SYNOPSIS $e = Search::Elasticsearch->new( cxn_pool => 'Static::NoPing' nodes => [ 'search1:9200', 'search2:9200' ], ); =head1 DESCRIPTION The L connection pool (like the L pool) should be used when your access to the cluster is limited. However, the C pool needs to be able to ping nodes in the cluster, with a C request. If you can't ping your nodes, then you should use the C connection pool instead. Because the cluster cannot be pinged, this CxnPool cannot use a short ping request to determine whether nodes are live or not - it just has to send requests to the nodes to determine whether they are alive or not. Most of the time, a dead node will cause the request to fail quickly. However, in situations where node failure takes time (eg malfunctioning routers or firewalls), a failure may not be reported until the request itself times out (see L). Failed nodes will be retried regularly to check if they have recovered. This class does L and L. =head1 CONFIGURATION =head2 C The list of nodes to use to serve requests. Can accept a single node, multiple nodes, and defaults to C if no C are specified. See L for details of the node specification. =head2 See also =over =item * L =item * L =item * L =back =head2 Inherited configuration From L =over =item * L =back From L =over =item * L =back =head1 METHODS =head2 C $cxn = $cxn_pool->next_cxn Returns the next available node in round robin fashion - either a live node which has previously responded successfully, or a previously failed node which should be retried. If all nodes are dead, it will throw a C error. =head2 Inherited methods From L =over =item * L =item * L =back From L =over =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =back =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut __END__ # ABSTRACT: A CxnPool for connecting to a remote cluster without the ability to ping. Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Role/0000775000175000017500000000000014133761217022467 5ustar enricoenricoSearch-Elasticsearch-7.715/lib/Search/Elasticsearch/Role/Is_Sync.pm0000644000175000017500000000262214133761217024374 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::Role::Is_Sync; $Search::Elasticsearch::Role::Is_Sync::VERSION = '7.715'; use Moo::Role; use namespace::clean; 1; # ABSTRACT: A role to mark classes which should be used with other sync classes __END__ =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Role::Is_Sync - A role to mark classes which should be used with other sync classes =head1 VERSION version 7.715 =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Role/Serializer.pm0000644000175000017500000000333514133761217025140 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::Role::Serializer; $Search::Elasticsearch::Role::Serializer::VERSION = '7.715'; use Moo::Role; requires qw(encode decode encode_pretty encode_bulk mime_type); 1; # ABSTRACT: An interface for Serializer modules __END__ =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Role::Serializer - An interface for Serializer modules =head1 VERSION version 7.715 =head1 DESCRIPTION There is no code in this module. It defines an interface for Serializer implementations, and requires the following methods: =over =item * C =item * C =item * C =item * C =item * C =back See L for more. =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Role/API.pm0000644000175000017500000000670014133761217023437 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::Role::API; $Search::Elasticsearch::Role::API::VERSION = '7.715'; use Moo::Role; requires 'api_version'; requires 'api'; use Scalar::Util qw(looks_like_number); use Search::Elasticsearch::Util qw(throw); use namespace::clean; our %Handler = ( string => \&_string, time => \&_string, date => \&_string, list => \&_list, boolean => \&_bool, enum => \&_list, number => \&_num, int => \&_num, float => \&_num, double => \&_num, "number|string" => \&_numOrString, ); #=================================== sub _bool { #=================================== my $val = _detect_bool(@_); return ( $val && $val ne 'false' ) ? 'true' : 'false'; } #=================================== sub _detect_bool { #=================================== my $val = shift; return '' unless defined $val; if ( ref $val eq 'SCALAR' ) { return 'false' if $$val eq 0; return 'true' if $$val eq 1; } elsif ( UNIVERSAL::isa( $val, "JSON::PP::Boolean" ) ) { return "$val" ? 'true' : 'false'; } return "$val"; } #=================================== sub _list { #=================================== return join ",", map { _detect_bool($_) } # ref $_[0] eq 'ARRAY' ? @{ $_[0] } : $_[0]; } #=================================== sub _num { #=================================== return 0 + $_[0]; } #=================================== sub _string { #=================================== return "$_[0]"; } #=================================== sub _numOrString { #=================================== if (looks_like_number($_[0])) { return _num($_[0]); } return _string($_[0]); } #=================================== sub _qs_init { #=================================== my $class = shift; my $API = shift; for my $spec ( keys %$API ) { my $qs = $API->{$spec}{qs}; for my $param ( keys %$qs ) { my $handler = $Handler{ $qs->{$param} } or throw( "Internal", "Unknown type <" . $qs->{$param} . "> for param <$param> in API <$spec>" ); $qs->{$param} = $handler; } } } 1; # ABSTRACT: Provides common functionality for API implementations __END__ =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Role::API - Provides common functionality for API implementations =head1 VERSION version 7.715 =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Role/CxnPool/0000775000175000017500000000000014133761217024051 5ustar enricoenricoSearch-Elasticsearch-7.715/lib/Search/Elasticsearch/Role/CxnPool/Sniff.pm0000644000175000017500000001342114133761217025453 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::Role::CxnPool::Sniff; $Search::Elasticsearch::Role::CxnPool::Sniff::VERSION = '7.715'; use Moo::Role; with 'Search::Elasticsearch::Role::CxnPool'; requires 'next_cxn', 'sniff'; use namespace::clean; use Search::Elasticsearch::Util qw(parse_params); use List::Util qw(min); use Try::Tiny; has 'sniff_interval' => ( is => 'ro', default => 300 ); has 'next_sniff' => ( is => 'rw', default => 0 ); has 'sniff_max_content_length' => ( is => 'ro' ); #=================================== sub BUILDARGS { #=================================== my ( $class, $params ) = parse_params(@_); $params->{sniff_max_content_length} = !$params->{max_content_length} unless defined $params->{sniff_max_content_length}; return $params; } #=================================== sub schedule_check { #=================================== my $self = shift; $self->logger->info("Require sniff before next request"); $self->next_sniff(-1); } #=================================== sub parse_sniff { #=================================== my $self = shift; my $nodes = shift or return; my @live_nodes; my $max = 0; my $sniff_max = $self->sniff_max_content_length; for my $node_id ( keys %$nodes ) { my $data = $nodes->{$node_id}; my $addr = $data->{http}{publish_address} || $data->{http_address}; my $host = $self->_extract_host($addr) or next; $host = $self->should_accept_node( $host, $node_id, $data ) or next; push @live_nodes, $host; next unless $sniff_max and $data->{http}; my $node_max = $data->{http}{max_content_length_in_bytes} || 0; $max = $node_max == 0 ? $max : $max == 0 ? $node_max : min( $node_max, $max ); } return unless @live_nodes; $self->cxn_factory->max_content_length($max) if $sniff_max and $max; $self->set_cxns(@live_nodes); my $next = $self->next_sniff( time() + $self->sniff_interval ); $self->logger->infof( "Next sniff at: %s", scalar localtime($next) ); return 1; } #=================================== sub _extract_host { #=================================== my $self = shift; my $host = shift || return; $host =~ s{^inet\[(.+)\]$}{$1}; $host =~ s{^[^/]*/}{}; return $host; } #=================================== sub should_accept_node { return $_[1] } #=================================== 1; =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Role::CxnPool::Sniff - A CxnPool role for connecting to a local cluster with a dynamic node list =head1 VERSION version 7.715 =head1 CONFIGURATION =head2 C How often should we perform a sniff in order to detect whether new nodes have been added to the cluster. Defaults to `300` seconds. =head2 C Whether we should set the L dynamically while sniffing. Defaults to true unless a fixed C was specified. =head1 METHODS =head2 C $cxn_pool->schedule_check Schedules a sniff before the next request is processed. =head2 C $bool = $cxn_pool->parse_sniff(\%nodes); Parses the response from a sniff request and extracts the hostname/ip of all listed nodes, filtered through L. If any live nodes are found, they are passed to L. The L is also detected if L is true. =head2 C $host = $cxn_pool->should_accept_node($host,$node_id,\%node_data) This method serves as a hook which can be overridden by the user. When a sniff is performed, this method is called with the C (eg C<192.168.5.100:9200>), the C (the ID assigned to the node by Elasticsearch) and the C which contains the information about the node that Elasticsearch has returned, eg: { "transport_address" => "inet[192.168.5.100/192.168.5.100:9300]", "http" : { "publish_address" => "inet[/192.168.5.100:9200]", "max_content_length" => "100mb", "bound_address" => "inet[/0:0:0:0:0:0:0:0:9200]", "max_content_length_in_bytes" : 104857600 }, "version" => "0.90.4", "name" => "Silver Sable", "hostname" => "search1.domain.com", "http_address" => "inet[/192.168.5.100:9200]" } If the node should be I (ie used to serve data), then it should return the C value to use. By default, nodes are always accepted. =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut __END__ # ABSTRACT: A CxnPool role for connecting to a local cluster with a dynamic node list Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Role/CxnPool/Static.pm0000644000175000017500000000442614133761217025642 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::Role::CxnPool::Static; $Search::Elasticsearch::Role::CxnPool::Static::VERSION = '7.715'; use Moo::Role; with 'Search::Elasticsearch::Role::CxnPool'; requires 'next_cxn'; use namespace::clean; #=================================== sub BUILD { #=================================== my $self = shift; $self->set_cxns( @{ $self->seed_nodes } ); $self->schedule_check; } #=================================== sub schedule_check { #=================================== my ($self) = @_; $self->logger->info("Forcing ping before next use on all live cxns"); for my $cxn ( @{ $self->cxns } ) { next if $cxn->is_dead; $self->logger->infof( "Ping [%s] before next request", $cxn->stringify ); $cxn->force_ping; } } 1; =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Role::CxnPool::Static - A CxnPool role for connecting to a remote cluster with a static list of nodes. =head1 VERSION version 7.715 =head1 METHODS =head2 C $cxn_pool->schedule_check Forces a ping on each cxn in L before the next time that cxn is used for a request. =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut __END__ # ABSTRACT: A CxnPool role for connecting to a remote cluster with a static list of nodes. Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Role/CxnPool/Static/0000775000175000017500000000000014133761217025300 5ustar enricoenricoSearch-Elasticsearch-7.715/lib/Search/Elasticsearch/Role/CxnPool/Static/NoPing.pm0000644000175000017500000000574414133761217027040 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::Role::CxnPool::Static::NoPing; $Search::Elasticsearch::Role::CxnPool::Static::NoPing::VERSION = '7.715'; use Moo::Role; with 'Search::Elasticsearch::Role::CxnPool'; use namespace::clean; has 'max_retries' => ( is => 'lazy' ); has '_dead_cxns' => ( is => 'ro', default => sub { [] } ); #=================================== sub next_cxn { #=================================== my $self = shift; my $cxns = $self->cxns; my $total = @$cxns; my $dead = $self->_dead_cxns; while ( $total-- ) { my $cxn = $cxns->[ $self->next_cxn_num ]; return $cxn if $cxn->is_live || $cxn->next_ping < time(); push @$dead, $cxn unless grep { $_ eq $cxn } @$dead; } if ( @$dead and $self->retries <= $self->max_retries ) { $_->force_ping for @$dead; return shift @$dead; } throw( "NoNodes", "No nodes are available: [" . $self->cxns_str . ']' ); } #=================================== sub _build_max_retries { @{ shift->cxns } - 1 } sub _max_retries { shift->max_retries + 1 } #=================================== #=================================== sub BUILD { #=================================== my $self = shift; $self->set_cxns( @{ $self->seed_nodes } ); } #=================================== sub should_mark_dead { #=================================== my ( $self, $error ) = @_; return $error->is( 'Cxn', 'Timeout' ); } #=================================== after 'reset_retries' => sub { #=================================== my $self = shift; @{ $self->_dead_cxns } = (); }; #=================================== sub schedule_check { } #=================================== 1; # ABSTRACT: A CxnPool for connecting to a remote cluster without the ability to ping. __END__ =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Role::CxnPool::Static::NoPing - A CxnPool for connecting to a remote cluster without the ability to ping. =head1 VERSION version 7.715 =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Role/CxnPool.pm0000644000175000017500000001761714133761217024421 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::Role::CxnPool; $Search::Elasticsearch::Role::CxnPool::VERSION = '7.715'; use Moo::Role; use Search::Elasticsearch::Util qw(parse_params); use List::Util qw(shuffle); use IO::Select(); use Time::HiRes qw(time sleep); use Search::Elasticsearch::Util qw(to_list); use namespace::clean; requires qw(next_cxn schedule_check); has 'cxn_factory' => ( is => 'ro', required => 1 ); has 'logger' => ( is => 'ro', required => 1 ); has 'serializer' => ( is => 'ro', required => 1 ); has 'current_cxn_num' => ( is => 'rwp', default => 0 ); has 'cxns' => ( is => 'rwp', default => sub { [] } ); has 'seed_nodes' => ( is => 'ro', required => 1 ); has 'retries' => ( is => 'rw', default => 0 ); has 'randomize_cxns' => ( is => 'ro', default => 1 ); #=================================== around BUILDARGS => sub { #=================================== my $orig = shift; my $params = $orig->(@_); my @seed = grep {$_} to_list( delete $params->{nodes} || ('') ); @seed = $params->{cxn_factory}->default_host unless @seed; $params->{seed_nodes} = \@seed; return $params; }; #=================================== sub next_cxn_num { #=================================== my $self = shift; my $cxns = $self->cxns; return unless @$cxns; my $current = $self->current_cxn_num; $self->_set_current_cxn_num( ( $current + 1 ) % @$cxns ); return $current; } #=================================== sub set_cxns { #=================================== my $self = shift; my $factory = $self->cxn_factory; my @cxns = map { $factory->new_cxn($_) } @_; @cxns = shuffle @cxns if $self->randomize_cxns; $self->_set_cxns( \@cxns ); $self->_set_current_cxn_num(0); $self->logger->infof( "Current cxns: %s", [ map { $_->stringify } @cxns ] ); return; } #=================================== sub request_ok { #=================================== my ( $self, $cxn ) = @_; $cxn->mark_live; $self->reset_retries; } #=================================== sub request_failed { #=================================== my ( $self, $cxn, $error ) = @_; if ( $error->is( 'Cxn', 'Timeout' ) ) { $cxn->mark_dead if $self->should_mark_dead($error); $self->schedule_check; if ( $self->should_retry($error) ) { my $retries = $self->retries( $self->retries + 1 ); return 1 if $retries < $self->_max_retries; } } else { $cxn->mark_live if $cxn; } $self->reset_retries; return 0; } #=================================== sub should_retry { #=================================== my ( $self, $error ) = @_; return $error->is('Cxn'); } #=================================== sub should_mark_dead { #=================================== my ( $self, $error ) = @_; return $error->is('Cxn'); } #=================================== sub cxns_str { #=================================== my $self = shift; join ", ", map { $_->stringify } @{ $self->cxns }; } #=================================== sub cxns_seeds_str { #=================================== my $self = shift; join ", ", ( map { $_->stringify } @{ $self->cxns } ), @{ $self->seed_nodes }; } #=================================== sub reset_retries { shift->retries(0) } sub _max_retries {2} #=================================== 1; =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Role::CxnPool - Provides common functionality to the CxnPool implementations =head1 VERSION version 7.715 =head1 DESCRIPTION See the CxnPool implementations: =over =item * L =item * L =item * L =back =head1 CONFIGURATION These configuration options should not be set by the user but are documented here for completeness. =head2 C By default, the order of cxns passed to L is randomized before they are stored. Set C to a false value to disable. =head1 METHODS =head2 C $factory = $cxn_pool->cxn_factory Returns the L object for creating a new C<$cxn> instance. =head2 C $logger = $cxn_pool->logger Returns the L-based object, which defaults to L. =head2 C $serializer = $cxn_pool->serializer Returns the L-based object, which defaults to L. =head2 C $num = $cxn_pool->current_cxn_num Returns the current cxn number, which is an offset into the array of cxns set by L. =head2 C \@cxns = $cxn_pool->cxns; Returns the current list of L-based cxn objects as set by L. =head2 C \@seed_nodes = $cxn_pool->seed_nodes Returns the list of C originally specified when calling L. =head2 C $num = $cxn_pool->next_cxn_num; Returns the number of the next connection, in round-robin fashion. Updates the L. =head2 C $cxn_pool->set_cxns(@nodes); Takes a list of nodes, converts them into L-based objects and makes them accessible via L. =head2 C $cxn_pool->request_ok($cxn); Called when a request by the specified C<$cxn> object has completed successfully. Marks the C<$cxn> as live. =head2 C $should_retry = $cxn_pool->request_failed($cxn,$error); Called when a request by the specified C<$cxn> object has failed. Returns C<1> if the request should be retried or C<0> if it shouldn't. =head2 C $bool = $cxn_pool->should_retry($error); Examines the error to decide whether the request should be retried or not. By default, only L errors are retried. =head2 C $bool = $cxn_pool->should_mark_dead($error); Examines the error to decide whether the C<$cxn> should be marked as dead or not. By default, only L errors cause a C<$cxn> to be marked as dead. =head2 C $str = $cxn_pool->cxns_str Returns all L as a string for logging purposes. =head2 C $str = $cxn_pool->cxns_seeeds_str Returns all L and L as a string for logging purposes. =head2 C $retries = $cxn_pool->retries The number of times the current request has been retried. =head2 C $cxn_pool->reset_retries; Called at the start of a new request to reset the retries count. =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut __END__ #ABSTRACT: Provides common functionality to the CxnPool implementations Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Role/Serializer/0000775000175000017500000000000014133761217024600 5ustar enricoenricoSearch-Elasticsearch-7.715/lib/Search/Elasticsearch/Role/Serializer/JSON.pm0000644000175000017500000001124214133761217025705 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::Role::Serializer::JSON; $Search::Elasticsearch::Role::Serializer::JSON::VERSION = '7.715'; use Moo::Role; requires 'JSON'; use Search::Elasticsearch::Util qw(throw); use Try::Tiny; use Encode qw(encode_utf8 decode_utf8 is_utf8); use namespace::clean; has 'mime_type' => ( is => 'ro', default => 'application/json' ); with 'Search::Elasticsearch::Role::Serializer'; #=================================== sub encode { #=================================== my ( $self, $var ) = @_; unless ( ref $var ) { return is_utf8($var) ? encode_utf8($var) : $var; } return try { $self->JSON->encode($var) } catch { throw( "Serializer", $_, { var => $var } ) }; } #=================================== sub encode_bulk { #=================================== my ( $self, $var ) = @_; unless ( ref $var ) { return is_utf8($var) ? encode_utf8($var) : $var; } my $json = ''; throw( "Param", "Var must be an array ref" ) unless ref $var eq 'ARRAY'; return try { for (@$var) { $json .= ( ref($_) ? $self->JSON->encode($_) : $_ ) . "\n"; } return $json; } catch { throw( "Serializer", $_, { var => $var } ) }; } #=================================== sub encode_pretty { #=================================== my ( $self, $var ) = @_; $self->JSON->pretty(1); my $json; try { $json = $self->encode($var); } catch { die "$_"; } finally { $self->JSON->pretty(0); }; return $json; } #=================================== sub decode { #=================================== my ( $self, $json ) = @_; return unless defined $json; return is_utf8($json) ? $json : decode_utf8($json) unless substr( $json, 0, 1 ) =~ /^[\[{]/; return try { $self->JSON->decode($json); } catch { throw( "Serializer", $_, { json => $json } ); }; } #=================================== sub _set_canonical { #=================================== shift()->JSON->canonical(1); } 1; =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Role::Serializer::JSON - A Serializer role for JSON modules =head1 VERSION version 7.715 =head1 DESCRIPTION This role encodes Perl data structures into JSON strings, and decodes JSON strings into Perl data structures. =head1 METHODS =head2 C $bytes = $serializer->encode($ref); $bytes = $serializer->encode($str); The L method converts array and hash refs into their JSON equivalents. If a string is passed in, it is returned as the UTF8 encoded version of itself. The empty string and C are returned as is. =head2 C $bytes = $serializer->encode_pretty($ref); $bytes = $serializer->encode_pretty($str); Works exactly as L but the JSON output is pretty-printed. =head2 C $bytes = $serializer->encode_bulk([\%hash,\%hash,...]); $bytes = $serializer->encode_bulk([$str,$str,...]); The L method expects an array ref of hashes or strings. Each hash or string is processed by L then joined together by newline characters, with a final newline character appended to the end. This is the special JSON format used for bulk requests. =head2 C $var = $serializer->decode($json_bytes); $str = $serializer->decode($bytes); If the passed in value looks like JSON (ie starts with a C<{> or C<[> character), then it is decoded from JSON, otherwise it is returned as the UTF8 decoded version of itself. The empty string and C are returned as is. =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut __END__ # ABSTRACT: A Serializer role for JSON modules Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Role/Cxn.pm0000644000175000017500000006042414133761217023561 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::Role::Cxn; $Search::Elasticsearch::Role::Cxn::VERSION = '7.715'; use Moo::Role; use Search::Elasticsearch::Util qw(parse_params throw to_list); use List::Util qw(min); use Try::Tiny; use URI(); use IO::Compress::Deflate(); use IO::Uncompress::Inflate(); use IO::Compress::Gzip(); use IO::Uncompress::Gunzip qw(gunzip $GunzipError); use Search::Elasticsearch::Util qw(to_list); use namespace::clean; use Net::IP; requires qw(perform_request error_from_text handle); has 'host' => ( is => 'ro', required => 1 ); has 'port' => ( is => 'ro', required => 1 ); has 'uri' => ( is => 'ro', required => 1 ); has 'request_timeout' => ( is => 'ro', default => 30 ); has 'ping_timeout' => ( is => 'ro', default => 2 ); has 'sniff_timeout' => ( is => 'ro', default => 1 ); has 'sniff_request_timeout' => ( is => 'ro', default => 2 ); has 'next_ping' => ( is => 'rw', default => 0 ); has 'ping_failures' => ( is => 'rw', default => 0 ); has 'dead_timeout' => ( is => 'ro', default => 60 ); has 'max_dead_timeout' => ( is => 'ro', default => 3600 ); has 'serializer' => ( is => 'ro', required => 1 ); has 'logger' => ( is => 'ro', required => 1 ); has 'handle_args' => ( is => 'ro', default => sub { {} } ); has 'default_qs_params' => ( is => 'ro', default => sub { {} } ); has 'scheme' => ( is => 'ro' ); has 'is_https' => ( is => 'ro' ); has 'userinfo' => ( is => 'ro' ); has 'max_content_length' => ( is => 'ro' ); has 'default_headers' => ( is => 'ro' ); has 'deflate' => ( is => 'ro' ); has 'gzip' => ( is => 'ro' ); has 'ssl_options' => ( is => 'ro', predicate => 'has_ssl_options' ); has 'handle' => ( is => 'lazy', clearer => 1 ); has '_pid' => ( is => 'rw', default => $$ ); my %Code_To_Error = ( 400 => 'Request', 401 => 'Unauthorized', 403 => 'Forbidden', 404 => 'Missing', 408 => 'RequestTimeout', 409 => 'Conflict', 413 => 'ContentLength', 502 => 'BadGateway', 503 => 'Unavailable', 504 => 'GatewayTimeout' ); #=================================== sub stringify { shift->uri . '' } #=================================== #=================================== sub get_user_agent { #=================================== return sprintf("elasticsearch-perl/%s (%s; perl %s)", $Search::Elasticsearch::VERSION, $^O, $]); } #=================================== sub BUILDARGS { #=================================== my ( $class, $params ) = parse_params(@_); my $node = $params->{node} || { host => 'localhost', port => '9200' }; unless ( ref $node eq 'HASH' ) { $node = "[$node]" if Net::IP::ip_is_ipv6($node); unless ( $node =~ m{^http(s)?://} ) { $node = ( $params->{use_https} ? 'https://' : 'http://' ) . $node; } if ( $params->{port} && $node !~ m{//[^/\[]+:\d+} ) { $node =~ s{(//[^/]+)}{$1:$params->{port}}; } my $uri = URI->new($node); $node = { scheme => $uri->scheme, host => $uri->host, port => $uri->port, path => $uri->path, userinfo => $uri->userinfo }; } my $host = $node->{host} || 'localhost'; my $userinfo = $node->{userinfo} || $params->{userinfo} || ''; my $scheme = $node->{scheme} || ( $params->{use_https} ? 'https' : 'http' ); my $port = $node->{port} || $params->{port} || ( $scheme eq 'http' ? 80 : 443 ); my $path = $node->{path} || $params->{path_prefix} || ''; $path =~ s{^/?}{/}g; $path =~ s{/+$}{}; my %default_headers = %{ $params->{default_headers} || {} }; if ($userinfo) { require MIME::Base64; my $auth = MIME::Base64::encode_base64( $userinfo, "" ); chomp $auth; $default_headers{Authorization} = "Basic $auth"; } if ( $params->{gzip} ) { $default_headers{'Accept-Encoding'} = "gzip"; } elsif ( $params->{deflate} ) { $default_headers{'Accept-Encoding'} = "deflate"; } $default_headers{'User-Agent'} = $class->get_user_agent(); $params->{scheme} = $scheme; $params->{is_https} = $scheme eq 'https'; $params->{host} = $host; $params->{port} = $port; $params->{path} = $path; $params->{userinfo} = $userinfo; $host = "[$host]" if Net::IP::ip_is_ipv6($host); $params->{uri} = URI->new("$scheme://$host:$port$path"); $params->{default_headers} = \%default_headers; return $params; } #=================================== before 'handle' => sub { #=================================== my $self = shift; if ( $$ != $self->_pid ) { $self->clear_handle; $self->_pid($$); } }; #=================================== sub is_live { !shift->next_ping } sub is_dead { !!shift->next_ping } #=================================== #=================================== sub mark_live { #=================================== my $self = shift; $self->ping_failures(0); $self->next_ping(0); } #=================================== sub mark_dead { #=================================== my $self = shift; my $fails = $self->ping_failures; $self->ping_failures( $fails + 1 ); my $timeout = min( $self->dead_timeout * 2**$fails, $self->max_dead_timeout ); my $next = $self->next_ping( time() + $timeout ); $self->logger->infof( 'Marking [%s] as dead. Next ping at: %s', $self->stringify, scalar localtime($next) ); } #=================================== sub force_ping { #=================================== my $self = shift; $self->ping_failures(0); $self->next_ping(-1); } #=================================== sub pings_ok { #=================================== my $self = shift; $self->logger->infof( 'Pinging [%s]', $self->stringify ); return try { $self->perform_request( { method => 'HEAD', path => '/', timeout => $self->ping_timeout, } ); $self->logger->infof( 'Marking [%s] as live', $self->stringify ); $self->mark_live; 1; } catch { $self->logger->debug("$_"); $self->mark_dead; 0; }; } #=================================== sub sniff { #=================================== my $self = shift; $self->logger->infof( 'Sniffing [%s]', $self->stringify ); return try { $self->perform_request( { method => 'GET', path => '/_nodes/http', qs => { timeout => $self->sniff_timeout . 's' }, timeout => $self->sniff_request_timeout, } )->{nodes}; } catch { $self->logger->debug($_); return; }; } #=================================== sub build_uri { #=================================== my ( $self, $params ) = @_; my $uri = $self->uri->clone; $uri->path( $uri->path . $params->{path} ); my %qs = ( %{ $self->default_qs_params }, %{ $params->{qs} || {} } ); $uri->query_form( \%qs ); return $uri; } #=================================== before 'perform_request' => sub { #=================================== my ( $self, $params ) = @_; return unless defined $params->{data}; $self->_compress_body($params); my $max = $self->max_content_length or return; return if length( $params->{data} ) < $max; $self->logger->throw_error( 'ContentLength', "Body is longer than max_content_length ($max)", ); }; #=================================== sub _compress_body { #=================================== my ( $self, $params ) = @_; my $output; if ( $self->gzip ) { IO::Compress::Gzip::gzip( \( $params->{data} ), \$output ) or throw( 'Request', "Couldn't gzip request: $IO::Compress::Gzip::GzipError" ); $params->{data} = $output; $params->{encoding} = 'gzip'; } elsif ( $self->deflate ) { IO::Compress::Deflate::deflate( \( $params->{data} ), \$output ) or throw( 'Request', "Couldn't deflate request: $IO::Compress::Deflate::DeflateError" ); $params->{data} = $output; $params->{encoding} = 'deflate'; } } #=================================== sub _decompress_body { #=================================== my ( $self, $body_ref, $headers ) = @_; if ( my $encoding = $headers->{'content-encoding'} ) { my $output; if ( $encoding eq 'gzip' ) { IO::Uncompress::Gunzip::gunzip( $body_ref, \$output ) or throw( 'Request', "Couldn't gunzip response: $IO::Uncompress::Gunzip::GunzipError" ); } elsif ( $encoding eq 'deflate' ) { IO::Uncompress::Inflate::inflate( $body_ref, \$output, Transparent => 0 ) or throw( 'Request', "Couldn't inflate response: $IO::Uncompress::Inflate::InflateError" ); } else { throw( 'Request', "Unknown content-encoding: $encoding" ); } ${$body_ref} = $output; } } #=================================== sub process_response { #=================================== my ( $self, $params, $code, $msg, $body, $headers ) = @_; $self->_decompress_body( \$body, $headers ); my ($mime_type) = split /\s*;\s*/, ( $headers->{'content-type'} || '' ); my $is_encoded = $mime_type && $mime_type ne 'text/plain'; # Deprecation warnings if ( my $warnings = $headers->{warning} ) { my $warning_string = _parse_warnings($warnings); my %temp = (%$params); delete $temp{data}; $self->logger->deprecation( $warning_string, \%temp ); } # Request is successful if ( $code >= 200 and $code <= 209 ) { if ( defined $body and length $body ) { $body = $self->serializer->decode($body) if $is_encoded; return $code, $body; } return ( $code, 1 ) if $params->{method} eq 'HEAD'; return ( $code, '' ); } # Check if the error should be ignored my @ignore = to_list( $params->{ignore} ); push @ignore, 404 if $params->{method} eq 'HEAD'; return ($code) if grep { $_ eq $code } @ignore; # Determine error type my $error_type = $Code_To_Error{$code}; unless ($error_type) { if ( defined $body and length $body ) { $msg = $body; $body = undef; } $error_type = $self->error_from_text( $code, $msg ); } delete $params->{data} if $params->{body}; my %error_args = ( status_code => $code, request => $params ); # Extract error message from the body, if present if ( $body = $self->serializer->decode($body) ) { $error_args{body} = $body; $msg = $self->_munge_elasticsearch_exception($body) || $msg; $error_args{current_version} = $1 if $error_type eq 'Conflict' and $msg =~ /: version conflict, current (?:version )?\[(\d+)\]/; } $msg ||= $error_type; chomp $msg; throw( $error_type, "[" . $self->stringify . "]-[$code] $msg", \%error_args ); } #=================================== sub _parse_warnings { #=================================== my @warnings = ref $_[0] eq 'ARRAY' ? @{ shift() } : shift(); my @str; for (@warnings) { if ( $_ =~ /^\d+\s+\S+\s+"((?:\\"|[^"])+)"/ ) { my $msg = $1; $msg =~ s/\\"/"/g, push @str, $msg; } else { push @str, $_; } } return join "; ", @str; } #=================================== sub _munge_elasticsearch_exception { #=================================== my ( $self, $body ) = @_; return $body unless ref $body eq 'HASH'; my $error = $body->{error} || return; return $error unless ref $error eq 'HASH'; my $root_causes = $error->{root_cause} || []; unless (@$root_causes) { my $msg = "[" . $error->{type} . "] " if $error->{type}; $msg .= $error->{reason} if $error->{reason}; return $msg; } my $json = $self->serializer; my @msgs; for (@$root_causes) { my %cause = (%$_); my $msg = "[" . ( delete $cause{type} ) . "] " . ( delete $cause{reason} ); if ( keys %cause ) { $msg .= ", with: " . $json->encode( \%cause ); } push @msgs, $msg; } return ( join ", ", @msgs ); } 1; # ABSTRACT: Provides common functionality to HTTP Cxn implementations __END__ =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Role::Cxn - Provides common functionality to HTTP Cxn implementations =head1 VERSION version 7.715 =head1 DESCRIPTION L provides common functionality to Cxn implementations. Cxn instances are created by a L implementation, using the L class. =head1 CONFIGURATION The configuration options are as follows: =head2 C A single C is passed to C by the L class. It can either be a URI or a hash containing each part. For instance: node => 'localhost'; # equiv of 'http://localhost:80' node => 'localhost:9200'; # equiv of 'http://localhost:9200' node => 'http://localhost:9200'; node => 'https://localhost'; # equiv of 'https://localhost:443' node => 'localhost/path'; # equiv of 'http://localhost:80/path' node => 'http://user:pass@localhost'; # equiv of 'http://localhost:80' # with userinfo => 'user:pass' Alternatively, a C can be specified as a hash: { scheme => 'http', host => 'search.domain.com', port => '9200', path => '/path', userinfo => 'user:pass' } Similarly, default values can be specified with C, C, C and C: $e = Search::Elasticsearch->new( port => 9201, path_prefix => '/path', userinfo => 'user:pass', use_https => 1, nodes => [ 'search1', 'search2' ] ) =head2 C By default, all backends that support HTTPS disable verification of the host they are connecting to. Use C to configure the type of verification that you would like the client to perform, or to configure the client to present its own certificate. The values accepted by C depend on the C class. See the documentation for the C class that you are using. =head2 C By default, Elasticsearch nodes accept a maximum post body of 100MB or C<104_857_600> bytes. This client enforces that limit. The limit can be customised with the C parameter (specified in bytes). If you're using the L module, then the C will be automatically retrieved from the live cluster, unless you specify a custom C: # max_content_length retrieved from cluster $e = Search::Elasticsearch->new( cxn_pool => 'Sniff' ); # max_content_length fixed at 10,000 bytes $e = Search::Elasticsearch->new( cxn_pool => 'Sniff', max_content_length => 10_000 ); =head2 C Enable Gzip compression of requests to and responses from Elasticsearch as follows: $e = Search::Elasticsearch->new( gzip => 1 ); =head2 C Enable Inflate/Deflate compression of requests to and responses from Elasticsearch as follows: $e = Search::Elasticsearch->new( deflate => 1 ); B The L, L, L, and L parameters default to values that allow this module to function with low powered hardware and slow networks. When you use Elasticsearch in production, you will probably want to reduce these timeout parameters to values that suit your environment. The configuration parameters are as follows: =head2 C $e = Search::Elasticsearch->new( request_timeout => 30 ); How long a normal request (ie not a ping or sniff request) should wait before throwing a C error. Defaults to C<30> seconds. B In production, no CRUD or search request should take 30 seconds to run, although admin tasks like C, C, or snapshot C may take much longer. A more reasonable value for production would be C<10> seconds or lower. =head2 C $e = Search::Elasticsearch->new( ping_timeout => 2 ); How long a ping request should wait before throwing a C error. Defaults to C<2> seconds. The L module pings nodes on first use, after any failure, and periodically to ensure that nodes are healthy. The C should be long enough to allow nodes respond in time, but not so long that sick nodes cause delays. A reasonable value for use in production on reasonable hardware would be C<0.3>-C<1> seconds. =head2 C $e = Search::Elasticsearch->new( dead_timeout => 60 ); How long a Cxn should be considered to be I (not used to serve requests), before it is retried. The default is C<60> seconds. This value is increased by powers of 2 for each time a request fails. In other words, the delay after each failure is as follows: Failure Delay 1 60 * 1 = 60 seconds 2 60 * 2 = 120 seconds 3 60 * 4 = 240 seconds 4 60 * 8 = 480 seconds 5 60 * 16 = 960 seconds =head2 C $e = Search::Elasticsearch->new( max_dead_timeout => 3600 ); The maximum delay that should be applied to a failed node. If the L calculation results in a delay greater than C (default C<3,600> seconds) then the C is used instead. In other words, dead nodes will be retried at least once every hour by default. =head2 C $e = Search::Elasticsearch->new( sniff_request_timeout => 2 ); How long a sniff request should wait before throwing a C error. Defaults to C<2> seconds. A reasonable value for production would be C<0.5>-C<2> seconds. =head2 C $e = Search::Elasticsearch->new( sniff_timeout => 1 ); How long the node being sniffed should wait for responses from other nodes before responding to the client. Defaults to C<1> second. A reasonable value in production would be C<0.3>-C<1> seconds. B The C is distinct from the L. For example, let's say you have a cluster with 5 nodes, 2 of which are unhealthy (taking a long time to respond): =over =item * If you sniff an unhealthy node, the request will throw a C error after C seconds. =item * If you sniff a healthy node, it will gather responses from the other nodes, and give up after C seconds, returning just the information it has managed to gather from the healthy nodes. =back B The C must be longer than the C to ensure that you get information about healthy nodes from the cluster. =head2 C Any default arguments which should be passed when creating a new instance of the class which handles the network transport, eg L. =head2 C $e = Search::Elasticsearch->new( default_qs_params => { session_key => 'my_session_key' } ); Any values passed to C will be added to the query string of every request. Also see L. =head1 METHODS None of the methods listed below are useful to the user. They are documented for those who are writing alternative implementations only. =head2 C $scheme = $cxn->scheme; Returns the scheme of the connection, ie C or C. =head2 C $bool = $cxn->is_https; Returns C or C depending on whether the C is C or not. =head2 C $userinfo = $cxn->userinfo Returns the username and password of the cxn, if any, eg C<"user:pass">. If C is provided, then a Basic Authorization header is added to each request. =head2 C $headers = $cxn->default_headers The default headers that are passed with each request. This includes the C header if C is true, and the C header if C has a value. Also see L. =head2 C $int = $cxn->max_content_length; Returns the maximum length in bytes that the HTTP body can have. =head2 C $uri = $cxn->build_uri({ path => '/_search', qs => { size => 10 }}); Returns the HTTP URI to use for a particular request, combining the passed in C parameter with any defined C, and adding the query-string parameters. =head1 METHODS None of the methods listed below are useful to the user. They are documented for those who are writing alternative implementations only. =head2 C $host = $cxn->host; The value of the C parameter, eg C. =head2 C $port = $cxn->port; The value of the C parameter, eg C<9200>. =head2 C $uri = $cxn->uri; A L object representing the node, eg C. =head2 C $bool = $cxn->is_dead Is the current node marked as I. =head2 C $bool = $cxn->is_live Is the current node marked as I. =head2 C $time = $cxn->next_ping($time) Get/set the time for the next scheduled ping. If zero, no ping is scheduled and the cxn is considered to be alive. If -1, a ping is scheduled before the next use. =head2 C $num = $cxn->ping_failures($num) The number of times that a cxn has been marked as dead. =head2 C $cxn->mark_dead Mark the cxn as I, set L and increment L. =head2 C Mark the cxn as I, set L and L to zero. =head2 C Set L to -1 (ie before next use) and L to zero. =head2 C $bool = $cxn->pings_ok Try to ping the node and call L or L depending on the success or failure of the ping. =head2 C $response = $cxn->sniff; Send a sniff request to the node and return the response. =head2 C ($code,$result) = $cxn->process_response($params, $code, $msg, $body ); Processes the response received from an Elasticsearch node and either returns the HTTP status code and the response body (deserialized from JSON) or throws an error of the appropriate type. The C<$params> are the original params passed to L, the C<$code> is the HTTP status code, the C<$msg> is the error message returned by the backend library and the C<$body> is the HTTP response body returned by Elasticsearch. =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Role/Logger.pm0000644000175000017500000001744414133761217024254 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::Role::Logger; $Search::Elasticsearch::Role::Logger::VERSION = '7.715'; use Moo::Role; use URI(); use Try::Tiny; use Search::Elasticsearch::Util qw(new_error); use namespace::clean; has 'serializer' => ( is => 'ro', required => 1 ); has 'log_as' => ( is => 'ro', default => 'elasticsearch.event' ); has 'trace_as' => ( is => 'ro', default => 'elasticsearch.trace' ); has 'deprecate_as' => ( is => 'ro', default => 'elasticsearch.deprecation' ); has 'log_to' => ( is => 'ro' ); has 'trace_to' => ( is => 'ro' ); has 'deprecate_to' => ( is => 'ro' ); has 'trace_handle' => ( is => 'lazy', handles => [qw( trace tracef is_trace)] ); has 'log_handle' => ( is => 'lazy', handles => [ qw( debug debugf is_debug info infof is_info warning warningf is_warning error errorf is_error critical criticalf is_critical ) ] ); has 'deprecate_handle' => ( is => 'lazy' ); #=================================== sub throw_error { #=================================== my ( $self, $type, $msg, $vars ) = @_; my $error = new_error( $type, $msg, $vars ); $self->error($error); die $error; } #=================================== sub throw_critical { #=================================== my ( $self, $type, $msg, $vars ) = @_; my $error = new_error( $type, $msg, $vars ); $self->critical($error); die $error; } #=================================== sub trace_request { #=================================== my ( $self, $cxn, $params ) = @_; return unless $self->is_trace; my $uri = URI->new( 'http://localhost:9200' . $params->{path} ); my %qs = ( %{ $params->{qs} }, pretty => "true" ); $uri->query_form( [ map { $_, $qs{$_} } sort keys %qs ] ); my $body = $params->{serialize} eq 'std' ? $self->serializer->encode_pretty( $params->{body} ) : $params->{data}; my $content_type = ''; if ( defined $body ) { $body =~ s/'/\\u0027/g; $body = " -d '\n$body'\n"; $content_type = '-H "Content-type: ' . $params->{mime_type} . '" '; } else { $body = "\n" } my $msg = sprintf( "# Request to: %s\n" # . "curl %s-X%s '%s'%s", # $cxn->stringify, $content_type, $params->{method}, $uri, $body ); $self->trace($msg); } #=================================== sub trace_response { #=================================== my ( $self, $cxn, $code, $response, $took ) = @_; return unless $self->is_trace; my $body = $self->serializer->encode_pretty($response) || "\n"; $body =~ s/^/# /mg; my $msg = sprintf( "# Response: %s, Took: %d ms\n%s", # $code, $took * 1000, $body ); $self->trace($msg); } #=================================== sub trace_error { #=================================== my ( $self, $cxn, $error ) = @_; return unless $self->is_trace; my $body = $self->serializer->encode_pretty( $error->{vars}{body} || "\n" ); $body =~ s/^/# /mg; my $msg = sprintf( "# ERROR: %s %s\n%s", ref($error), $error->{text}, $body ); $self->trace($msg); } #=================================== sub trace_comment { #=================================== my ( $self, $comment ) = @_; return unless $self->is_trace; $comment =~ s/^/# *** /mg; chomp $comment; $self->trace("$comment\n"); } #=================================== sub deprecation { #=================================== my $self = shift; $self->deprecate_handle->warnf( "[DEPRECATION] %s - In request: %s", @_ ); } 1; # ABSTRACT: Provides common functionality to Logger implementations __END__ =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Role::Logger - Provides common functionality to Logger implementations =head1 VERSION version 7.715 =head1 DESCRIPTION This role provides common functionality to Logger implementations, to enable the logging of events and the tracing of request-response conversations with Elasticsearch nodes. See L for the default implementation. =head1 CONFIGURATION =head2 C Parameters passed to C are used by L implementations to setup the L. See L for details. =head2 C By default, events emitted by L, L, L, L and L are logged to the L under the category C<"elasticsearch.event">, which can be configured with C. =head2 C Parameters passed to C are used by L implementations to setup the L. See L for details. =head2 C By default, trace output emitted by L, L, L and L are logged under the category C, which can be configured with C. =head2 C Parameters passed to C are used by L implementations to setup the L. See L for details. =head2 C By default, events emitted by L are logged to the L under the category C<"elasticsearch.deprecation">, which can be configured with C. =head1 METHODS =head2 C Returns an object which can handle the methods: C, C, C, C, C, C, C, C, C, C, C, C, C, C and C. =head2 C Returns an object which can handle the methods: C, C and C. =head2 C Returns an object which can handle the C method. =head2 C $logger->trace_request($cxn,\%request); Accepts a Cxn object and request parameters and logs them if tracing is enabled. =head2 C $logger->trace_response($cxn,$code,$response,$took); Logs a successful HTTP response, where C<$code> is the HTTP status code, C<$response> is the HTTP body and C<$took> is the time the request took in seconds =head2 C $logger->trace_error($cxn,$error); Logs a failed HTTP response, where C<$error> is an L object. =head2 C $logger->trace_comment($comment); Used to insert debugging comments into trace output. =head2 C $logger->deprecation($warning,$request) Issues a deprecation warning to the deprecation logger. =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Role/Transport.pm0000644000175000017500000000462114133761217025022 0ustar enricoenrico# Licensed to Elasticsearch B.V under one or more agreements. # Elasticsearch B.V licenses this file to you under the Apache 2.0 License. # See the LICENSE file in the project root for more information package Search::Elasticsearch::Role::Transport; $Search::Elasticsearch::Role::Transport::VERSION = '7.715'; use Moo::Role; requires qw(perform_request); use Try::Tiny; use Search::Elasticsearch::Util qw(parse_params is_compat); use namespace::clean; has 'serializer' => ( is => 'ro', required => 1 ); has 'logger' => ( is => 'ro', required => 1 ); has 'send_get_body_as' => ( is => 'ro', default => 'GET' ); has 'cxn_pool' => ( is => 'ro', required => 1 ); #=================================== sub BUILD { #=================================== my $self = shift; my $pool = $self->cxn_pool; is_compat( 'cxn_pool', $self, $pool ); is_compat( 'cxn', $self, $pool->cxn_factory->cxn_class ); return $self; } #=================================== sub tidy_request { #=================================== my ( $self, $params ) = parse_params(@_); $params->{method} ||= 'GET'; $params->{path} ||= '/'; $params->{qs} ||= {}; $params->{ignore} ||= []; my $body = $params->{body}; return $params unless defined $body; $params->{serialize} ||= 'std'; $params->{data} = $params->{serialize} eq 'std' ? $self->serializer->encode($body) : $self->serializer->encode_bulk($body); if ( $params->{method} eq 'GET' ) { my $send_as = $self->send_get_body_as; if ( $send_as eq 'POST' ) { $params->{method} = 'POST'; } elsif ( $send_as eq 'source' ) { $params->{qs}{source} = delete $params->{data}; delete $params->{body}; } } $params->{mime_type} ||= $self->serializer->mime_type; return $params; } 1; #ABSTRACT: Transport role providing interface between the client class and the Elasticsearch cluster __END__ =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Role::Transport - Transport role providing interface between the client class and the Elasticsearch cluster =head1 VERSION version 7.715 =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Role/Client/0000775000175000017500000000000014133761217023705 5ustar enricoenricoSearch-Elasticsearch-7.715/lib/Search/Elasticsearch/Role/Client/Direct.pm0000644000175000017500000001534014133761217025456 0ustar enricoenrico# Licensed to Elasticsearch B.V under one or more agreements. # Elasticsearch B.V licenses this file to you under the Apache 2.0 License. # See the LICENSE file in the project root for more information package Search::Elasticsearch::Role::Client::Direct; $Search::Elasticsearch::Role::Client::Direct::VERSION = '7.715'; use Moo::Role; with 'Search::Elasticsearch::Role::Client'; use Search::Elasticsearch::Util qw(load_plugin is_compat throw); use Try::Tiny; use Package::Stash 0.34 (); use Any::URI::Escape qw(uri_escape); use namespace::clean; #=================================== sub parse_request { #=================================== my $self = shift; my $defn = shift || {}; my $params = { ref $_[0] ? %{ shift() } : @_ }; my $request; try { $request = { ignore => delete $params->{ignore} || [], method => $defn->{method} || 'GET', serialize => $defn->{serialize} || 'std', path => $self->_parse_path( $defn, $params ), body => $self->_parse_body( $defn->{body}, $params ), qs => $self->_parse_qs( $defn->{qs}, $params ), }; } catch { chomp $_; my $name = $defn->{name} || ''; $self->logger->throw_error( 'Param', "$_ in ($name) request. " ); }; return $request; } #=================================== sub _parse_path { #=================================== my ( $self, $defn, $params ) = @_; return delete $params->{path} if $params->{path}; my $paths = $defn->{paths}; my $parts = $defn->{parts}; my %args; keys %$parts; no warnings 'uninitialized'; while ( my ( $key, $req ) = each %$parts ) { my $val = delete $params->{$key}; if ( ref $val eq 'ARRAY' ) { die "Param ($key) must contain a single value\n" if @$val > 1 and not $req->{multi}; $val = join ",", @$val; } if ( !length $val ) { die "Missing required param ($key)\n" if $req->{required}; next; } utf8::encode($val); $args{$key} = uri_escape($val); } PATH: for my $path (@$paths) { my @keys = keys %{ $path->[0] }; next PATH unless @keys == keys %args; for (@keys) { next PATH unless exists $args{$_}; } my ( $pos, @parts ) = @$path; for ( keys %$pos ) { $parts[ $pos->{$_} ] = $args{$_}; } return join "/", '', @parts; } throw( 'Internal', "Couldn't determine path", { params => $params, defn => $defn } ); } #=================================== sub _parse_body { #=================================== my ( $self, $defn, $params ) = @_; if ( defined $defn ) { die("Missing required param (body)\n") if $defn->{required} && !$params->{body}; return delete $params->{body}; } die("Unknown param (body)\n") if $params->{body}; return undef; } #=================================== sub _parse_qs { #=================================== my ( $self, $handlers, $params ) = @_; die "No (qs) defined\n" unless $handlers; my %qs; if ( my $raw = delete $params->{params} ) { die("Arg (params) shoud be a hashref\n") unless ref $raw eq 'HASH'; %qs = %$raw; } for my $key ( keys %$params ) { my $handler = $handlers->{$key} or die("Unknown param ($key)\n"); $qs{$key} = $handler->( delete $params->{$key} ); } return \%qs; } #=================================== sub _install_api { #=================================== my ( $class, $group ) = @_; my $defns = $class->api; my $stash = Package::Stash->new($class); my $group_qr = $group ? qr/$group\./ : qr//; for my $action ( keys %$defns ) { my ($name) = ( $action =~ /^$group_qr([^.]+)$/ ) or next; next if $stash->has_symbol( '&' . $name ); my %defn = ( name => $name, %{ $defns->{$action} } ); $stash->add_symbol( '&' . $name => sub { shift->perform_request( \%defn, @_ ); } ); } } #=================================== sub _build_namespace { #=================================== my ( $self, $ns ) = @_; my $class = load_plugin( $self->_namespace, [$ns] ); return $class->new( { transport => $self->transport, logger => $self->logger } ); } #=================================== sub _build_helper { #=================================== my ( $self, $name, $sub_class ) = @_; my $class = load_plugin( 'Search::Elasticsearch', $sub_class ); is_compat( $name . '_helper_class', $self->transport, $class ); return $class; } 1; # ABSTRACT: Request parsing for Direct clients __END__ =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Role::Client::Direct - Request parsing for Direct clients =head1 VERSION version 7.715 =head1 DESCRIPTION This role provides the single C method for classes which need to parse an API definition from L and convert it into a request which can be passed to L. =head1 METHODS =head2 C $request = $client->parse_request(\%defn,\%params); The C<%defn> is a definition returned by L with an extra key C which should be the name of the method that was called on the client. For instance if the user calls C<< $client->search >>, then the C should be C<"search">. C will turn the parameters that have been passed in into a C (via L), a query-string hash (via L) and will through a C value directly. B If a C key is specified in the C<%params> then it will be used directly, instead of trying to build path from the path template. Similarly, if a C key is specified in the C<%params>, then it will be used as a basis for the query string hash. For instance: $client->perform_request( { method => 'GET', name => 'new_method' }, { path => '/new/method', params => { foo => 'bar' }, body => \%body } ); This makes it easy to add support for custom plugins or new functionality not yet supported by the released client. =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Role/Client.pm0000644000175000017500000000313114133761217024237 0ustar enricoenrico# Licensed to Elasticsearch B.V under one or more agreements. # Elasticsearch B.V licenses this file to you under the Apache 2.0 License. # See the LICENSE file in the project root for more information package Search::Elasticsearch::Role::Client; $Search::Elasticsearch::Role::Client::VERSION = '7.715'; use Moo::Role; use namespace::clean; requires 'parse_request'; has 'transport' => ( is => 'ro', required => 1 ); has 'logger' => ( is => 'ro', required => 1 ); #=================================== sub perform_request { #=================================== my $self = shift; my $request = $self->parse_request(@_); return $self->transport->perform_request($request); } 1; =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Role::Client - Provides common functionality for Client implementations =head1 VERSION version 7.715 =head1 DESCRIPTION This role provides a common C method for Client implementations. =head1 METHODS =head2 C This method takes whatever arguments it is passed and passes them directly to a C method (which should be provided by Client implementations). The C method should return a request suitable for passing to L. =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut __END__ # ABSTRACT: Provides common functionality for Client implementations Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Util.pm0000644000175000017500000000753614133761217023052 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::Util; $Search::Elasticsearch::Util::VERSION = '7.715'; use Moo; use Search::Elasticsearch::Error(); use Scalar::Util qw(blessed); use Module::Runtime qw(compose_module_name is_module_name use_module); use Sub::Exporter -setup => { exports => [ qw( parse_params to_list load_plugin new_error throw upgrade_error is_compat ) ] }; #=================================== sub to_list { #=================================== grep {defined} ref $_[0] eq 'ARRAY' ? @{ $_[0] } : @_; } #=================================== sub parse_params { #=================================== my $self = shift; my %params; if ( @_ % 2 ) { throw( "Param", 'Expecting a HASH ref or a list of key-value pairs', { params => \@_ } ) unless ref $_[0] eq 'HASH'; %params = %{ shift() }; } else { %params = @_; } return ( $self, \%params ); } #=================================== sub load_plugin { #=================================== my ( $base, $spec ) = @_; $spec ||= "+$base"; return $spec if blessed $spec; my ( $class, $version ); if ( ref $spec eq 'ARRAY' ) { ( $class, $version ) = @$spec; } else { $class = $spec; } unless ( $class =~ s/\A\+// ) { $class = compose_module_name( $base, $class ); } $version ? use_module( $class, $version ) : use_module($class); } #=================================== sub throw { #=================================== my ( $type, $msg, $vars ) = @_; die Search::Elasticsearch::Error->new( $type, $msg, $vars, 1 ); } #=================================== sub new_error { #=================================== my ( $type, $msg, $vars ) = @_; return Search::Elasticsearch::Error->new( $type, $msg, $vars, 1 ); } #=================================== sub upgrade_error { #=================================== my ( $error, $vars ) = @_; return ref($error) && $error->isa('Search::Elasticsearch::Error') ? $error : Search::Elasticsearch::Error->new( "Internal", $error, $vars || {}, 1 ); } #=================================== sub is_compat { #=================================== my ( $attr, $one, $two ) = @_; my $role = $one->does('Search::Elasticsearch::Role::Is_Sync') ? 'Search::Elasticsearch::Role::Is_Sync' : 'Search::Elasticsearch::Role::Is_Async'; return if eval { $two->does($role); }; my $class = ref($two) || $two; die "$attr ($class) does not do $role"; } 1; # ABSTRACT: A utility class for internal use by Search::Elasticsearch __END__ =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Util - A utility class for internal use by Search::Elasticsearch =head1 VERSION version 7.715 =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Serializer/0000775000175000017500000000000014133761217023677 5ustar enricoenricoSearch-Elasticsearch-7.715/lib/Search/Elasticsearch/Serializer/JSON.pm0000644000175000017500000000444714133761217025015 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::Serializer::JSON; $Search::Elasticsearch::Serializer::JSON::VERSION = '7.715'; use Moo; use JSON::MaybeXS 1.002002 (); has 'JSON' => ( is => 'ro', default => sub { JSON::MaybeXS->new->utf8(1) } ); with 'Search::Elasticsearch::Role::Serializer::JSON'; use namespace::clean; 1; # ABSTRACT: The default JSON Serializer, using JSON::MaybeXS __END__ =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Serializer::JSON - The default JSON Serializer, using JSON::MaybeXS =head1 VERSION version 7.715 =head1 SYNOPSIS $e = Search::Elasticsearch( # serializer => 'JSON' ); =head1 DESCRIPTION This default Serializer class chooses between: =over =item * L =item * L =item * L =back First it checks if either L or L is already loaded and, if so, uses the appropriate backend. Otherwise it tries to load L, then L and finally L. If you would prefer to specify a particular JSON backend, then you can do so by using one of these modules: =over =item * L =item * L =item * L =back See their documentation for details. =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Serializer/JSON/0000775000175000017500000000000014133761217024450 5ustar enricoenricoSearch-Elasticsearch-7.715/lib/Search/Elasticsearch/Serializer/JSON/PP.pm0000644000175000017500000000422114133761217025322 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::Serializer::JSON::PP; $Search::Elasticsearch::Serializer::JSON::PP::VERSION = '7.715'; use Moo; use JSON::PP; has 'JSON' => ( is => 'ro', default => sub { JSON::PP->new->utf8(1) } ); with 'Search::Elasticsearch::Role::Serializer::JSON'; 1; # ABSTRACT: A JSON Serializer using JSON::PP __END__ =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Serializer::JSON::PP - A JSON Serializer using JSON::PP =head1 VERSION version 7.715 =head1 SYNOPSIS $e = Search::Elasticsearch( serializer => 'JSON::PP' ); =head1 DESCRIPTION While the default serializer, L, tries to choose the appropriate JSON backend, this module allows you to choose the L backend specifically. B You should really install and use either L or L as they are much much faster than L. This class does L. =head1 SEE ALSO =over =item * L =item * L =item * L =back =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Serializer/JSON/XS.pm0000644000175000017500000000402214133761217025334 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::Serializer::JSON::XS; $Search::Elasticsearch::Serializer::JSON::XS::VERSION = '7.715'; use Moo; use JSON::XS 2.26; has 'JSON' => ( is => 'ro', default => sub { JSON::XS->new->utf8(1) } ); with 'Search::Elasticsearch::Role::Serializer::JSON'; 1; =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Serializer::JSON::XS - A JSON Serializer using JSON::XS =head1 VERSION version 7.715 =head1 SYNOPSIS $e = Search::Elasticsearch( serializer => 'JSON::XS' ); =head1 DESCRIPTION While the default serializer, L, tries to choose the appropriate JSON backend, this module allows you to choose the L backend specifically. This class does L. =head1 SEE ALSO =over =item * L =item * L =item * L =back =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut __END__ # ABSTRACT: A JSON Serializer using JSON::XS Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Serializer/JSON/Cpanel.pm0000644000175000017500000000410514133761217026206 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::Serializer::JSON::Cpanel; $Search::Elasticsearch::Serializer::JSON::Cpanel::VERSION = '7.715'; use Cpanel::JSON::XS; use Moo; has 'JSON' => ( is => 'ro', default => sub { Cpanel::JSON::XS->new->utf8(1) } ); with 'Search::Elasticsearch::Role::Serializer::JSON'; 1; =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Serializer::JSON::Cpanel - A JSON Serializer using Cpanel::JSON::XS =head1 VERSION version 7.715 =head1 SYNOPSIS $e = Search::Elasticsearch( serializer => 'JSON::Cpanel' ); =head1 DESCRIPTION While the default serializer, L, tries to choose the appropriate JSON backend, this module allows you to choose the L backend specifically. This class does L. =head1 SEE ALSO =over =item * L =item * L =item * L =back =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut __END__ # ABSTRACT: A JSON Serializer using Cpanel::JSON::XS Search-Elasticsearch-7.715/lib/Search/Elasticsearch/TestServer.pm0000644000175000017500000002053314133761217024233 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::TestServer; $Search::Elasticsearch::TestServer::VERSION = '7.715'; use Moo; use Search::Elasticsearch(); use POSIX 'setsid'; use File::Temp(); use IO::Socket(); use HTTP::Tiny; use Search::Elasticsearch::Util qw(parse_params throw); use namespace::clean; has 'es_home' => ( is => 'ro', default => $ENV{ES_HOME} ); has 'es_version' => ( is => 'ro', default => $ENV{ES_VERSION} ); has 'instances' => ( is => 'ro', default => 1 ); has 'http_port' => ( is => 'ro', default => 9600 ); has 'es_port' => ( is => 'ro', default => 9700 ); has 'pids' => ( is => 'ro', default => sub { [] }, clearer => 1, predicate => 1 ); has 'dirs' => ( is => 'ro', default => sub { [] } ); has 'conf' => ( is => 'ro', default => sub { [] } ); has '_starter_pid' => ( is => 'rw', required => 0, predicate => 1 ); #=================================== sub start { #=================================== my $self = shift; my $home = $self->es_home or throw( 'Param', "Missing required param " ); $self->es_version or throw( 'Param', "Missing required param " ); my $instances = $self->instances; my $port = $self->http_port; my $es_port = $self->es_port; my @http = map { $port++ } ( 1 .. $instances ); my @transport = map { $es_port++ } ( 1 .. $instances ); $self->_check_ports( @http, @transport ); my $old_SIGINT = $SIG{INT}; $SIG{INT} = sub { $self->shutdown; if ( ref $old_SIGINT eq 'CODE' ) { return $old_SIGINT->(); } exit(1); }; for ( 0 .. $instances - 1 ) { my $dir = File::Temp->newdir(); push @{ $self->dirs }, $dir; print "Starting node: http://127.0.0.1:$http[$_]\n"; $self->_start_node( $dir, $transport[$_], $http[$_] ); } $self->_check_nodes(@http); return [ map {"http://127.0.0.1:$_"} @http ]; } #=================================== sub _check_ports { #=================================== my $self = shift; for my $port (@_) { next unless IO::Socket::INET->new("127.0.0.1:$port"); throw( 'Param', "There is already a service running on 127.0.0.1:$port. " . "Please shut it down before starting the test server" ); } } #=================================== sub _check_nodes { #=================================== my $self = shift; my $http = HTTP::Tiny->new; for my $node (@_) { print "Checking node: http://127.0.0.1:$node\n"; my $i = 20; while (1) { last if $http->head("http://127.0.0.1:$node/")->{status} == 200; throw( 'Cxn', "Couldn't connect to http://127.0.0.1:$node" ) unless $i--; sleep 1; } } } #=================================== sub _start_node { #=================================== my ( $self, $dir, $transport, $http ) = @_; my $pid_file = File::Temp->new; my @config = $self->_command_line( $pid_file, $dir, $transport, $http ); my $int_caught = 0; { local $SIG{INT} = sub { $int_caught++; }; defined( my $pid = fork ) or throw( 'Internal', "Couldn't fork a new process: $!" ); if ( $pid == 0 ) { throw( 'Internal', "Can't start a new session: $!" ) if setsid == -1; exec(@config) or die "Couldn't execute @config: $!"; } else { for ( 1 .. 5 ) { last if -s $pid_file->filename(); sleep 1; } open my $pid_fh, '<', $pid_file->filename; my $pid = <$pid_fh>; throw( 'Internal', "No PID file found for Elasticsearch" ) unless $pid; chomp $pid; push @{ $self->{pids} }, $pid; $self->_starter_pid($$); } } $SIG{INT}->('INT') if $int_caught; } #=================================== sub guarded_shutdown { #=================================== my $self = shift; if ( $self->_has_starter_pid && $$ == $self->_starter_pid ) { $self->shutdown(); } } #=================================== sub shutdown { #=================================== my $self = shift; local $?; return unless $self->has_pids; my $pids = $self->pids; $self->clear_pids; return unless @$pids; kill 9, @$pids; $self->clear_dirs; } #=================================== sub _command_line { #=================================== my ( $self, $pid_file, $dir, $transport, $http ) = @_; my $version = $self->es_version; my $class = "Search::Elasticsearch::Client::${version}::TestServer"; eval "require $class" || die $@; return $class->command_line(@_); } #=================================== sub clear_dirs { #=================================== my $self = shift; @{ $self->dirs() } = (); } #=================================== sub DEMOLISH { shift->guarded_shutdown } #=================================== 1; # ABSTRACT: A helper class to launch Elasticsearch nodes __END__ =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::TestServer - A helper class to launch Elasticsearch nodes =head1 VERSION version 7.715 =head1 SYNOPSIS use Search::Elasticsearch; use Search::Elasticsearch::TestServer; my $server = Search::Elasticsearch::TestServer->new( es_home => '/path/to/elasticsearch', # defaults to $ENV{ES_HOME} es_version => '6_0' # defaults to $ENV{ES_VERSION} ); my $nodes = $server->start; my $es = Search::Elasticsearch->new( nodes => $nodes ); # run tests $server->shutdown; =head1 DESCRIPTION The L class can be used to launch one or more instances of Elasticsearch for testing purposes. The nodes will be shutdown automatically. =head1 METHODS =head2 C my $server = Search::Elasticsearch::TestServer->new( es_home => '/path/to/elasticsearch', es_version => '6_0', instances => 1, http_port => 9600, es_port => 9700, conf => ['attr.foo=bar'], ); Params: =over =item * C Required. Must point to the Elasticsearch home directory, which contains C<./bin/elasticsearch>. Defaults to C<$ENV{ES_HOME}> =item * C Required. Accepts a version of the client, eg `6_0`, `5_0`, `2_0`, `1_0`, `0_90`. Defaults to C<$ENV{ES_VERSION}>. =item * C The number of nodes to start. Defaults to 1 =item * C The port to use for HTTP. If multiple instances are started, the C will be incremented for each subsequent instance. Defaults to 9600. =item * C The port to use for Elasticsearch's internal transport. If multiple instances are started, the C will be incremented for each subsequent instance. Defaults to 9700 =item * C An array containing any extra startup options that should be passed to Elasticsearch. =back =head1 C $nodes = $server->start; Starts the required instances and returns an array ref containing the IP and port of each node, suitable for passing to L: $es = Search::Elasticsearch->new( nodes => $nodes ); =head1 C $server->shutdown; Kills the running instances. This will be called automatically when C<$server> goes out of scope or if the program receives a C. =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Transport.pm0000644000175000017500000001067114133761217024123 0ustar enricoenrico# Licensed to Elasticsearch B.V under one or more agreements. # Elasticsearch B.V licenses this file to you under the Apache 2.0 License. # See the LICENSE file in the project root for more information package Search::Elasticsearch::Transport; $Search::Elasticsearch::Transport::VERSION = '7.715'; use Moo; use URI(); use Time::HiRes qw(time); use Try::Tiny; use Search::Elasticsearch::Util qw(upgrade_error); use namespace::clean; with 'Search::Elasticsearch::Role::Is_Sync', 'Search::Elasticsearch::Role::Transport'; #=================================== sub perform_request { #=================================== my $self = shift; my $params = $self->tidy_request(@_); my $pool = $self->cxn_pool; my $logger = $self->logger; my ( $code, $response, $cxn, $error ); try { $cxn = $pool->next_cxn; my $start = time(); $logger->trace_request( $cxn, $params ); ( $code, $response ) = $cxn->perform_request($params); $pool->request_ok($cxn); $logger->trace_response( $cxn, $code, $response, time() - $start ); } catch { $error = upgrade_error( $_, { request => $params, status_code => $code, body => $response } ); }; if ($error) { if ( $pool->request_failed( $cxn, $error ) ) { $logger->debugf( "[%s] %s", $cxn->stringify, "$error" ); $logger->info('Retrying request on a new cxn'); return $self->perform_request($params); } $logger->trace_error( $cxn, $error ); $error->is('NoNodes') ? $logger->throw_critical($error) : $logger->throw_error($error); } return $response; } 1; #ABSTRACT: Provides interface between the client class and the Elasticsearch cluster __END__ =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Transport - Provides interface between the client class and the Elasticsearch cluster =head1 VERSION version 7.715 =head1 DESCRIPTION The Transport class manages the request cycle. It receives parsed requests from the (user-facing) client class, and tries to execute the request on a node in the cluster, retrying a request if necessary. This class does L and L. =head1 CONFIGURATION =head2 C $e = Search::Elasticsearch->new( send_get_body_as => 'POST' ); Certain endpoints like L default to using a C method, even when they include a request body. Some proxy servers do not support C requests with a body. To work around this, the C parameter accepts the following: =over =item * C The default. Request bodies are sent as C requests. =item * C The method is changed to C when a body is present. =item * C The body is encoded as JSON and added to the query string as the C parameter. This has the advantage of still being a C request (for those filtering on request method) but has the disadvantage of being restricted in size. The limit depends on the proxies between the client and Elasticsearch, but usually is around 4kB. =back =head1 METHODS =head2 C Raw requests can be executed using the transport class as follows: $result = $e->transport->perform_request( method => 'POST', path => '/_search', qs => { from => 0, size => 10 }, body => { query => { match => { title => "Elasticsearch clients" } } } ); Other than the C, C, C and C parameters, which should be self-explanatory, it also accepts: =over =item C The HTTP error codes which should be ignored instead of throwing an error, eg C<404 NOT FOUND>: $result = $e->transport->perform_request( method => 'GET', path => '/index/type/id' ignore => [404], ); =item C Whether the C should be serialized in the standard way (as plain JSON) or using the special I format: C<"std"> or C<"bulk">. =back =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Client/0000775000175000017500000000000014133761217023004 5ustar enricoenricoSearch-Elasticsearch-7.715/lib/Search/Elasticsearch/Client/7_0/0000775000175000017500000000000014133761217023371 5ustar enricoenricoSearch-Elasticsearch-7.715/lib/Search/Elasticsearch/Client/7_0/Role/0000775000175000017500000000000014133761217024272 5ustar enricoenricoSearch-Elasticsearch-7.715/lib/Search/Elasticsearch/Client/7_0/Role/API.pm0000644000175000017500000067247214133761217025261 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::Client::7_0::Role::API; $Search::Elasticsearch::Client::7_0::Role::API::VERSION = '7.715'; use Moo::Role; with 'Search::Elasticsearch::Role::API'; use Search::Elasticsearch::Util qw(throw); use namespace::clean; has 'api_version' => ( is => 'ro', default => '7_0' ); our %API; #=================================== sub api { #=================================== my $name = $_[1] || return \%API; return $API{$name} || throw( 'Internal', "Unknown api name ($name)" ); } #=================================== %API = ( #=================================== 'bulk.metadata' => { params => { '_index' => '_index', 'index' => '_index', '_id' => '_id', 'id' => '_id', 'pipeline' => 'pipeline', 'routing' => 'routing', '_routing' => 'routing', 'parent' => 'parent', '_parent' => 'parent', 'timestamp' => 'timestamp', '_timestamp' => 'timestamp', 'ttl' => 'ttl', '_ttl' => 'ttl', 'version' => 'version', '_version' => 'version', 'version_type' => 'version_type', '_version_type' => 'version_type', 'if_seq_no' => 'if_seq_no', 'if_primary_term' => 'if_primary_term', 'lang' => 'lang', 'require_alias' => 'require_alias', 'refresh' => 'refresh', 'retry_on_conflict' => 'retru_on_conflict', 'wait_for_active_shards' => 'wait_for_active_shards', '_source' => '_source', '_source_excludes' => '_source_excludes', '_source_includes' => '_source_includes', 'timeout' => 'timeout' } }, 'bulk.update' => { params => [ '_source', '_source_includes', '_source_excludes', 'detect_noop', 'doc', 'doc_as_upsert', 'fields', 'retry_on_conflict', 'scripted_upsert', 'script', 'upsert', 'lang', 'params' ] }, 'bulk.required' => { params => ['index'] }, #=== AUTOGEN - START === 'bulk' => { body => { required => 1 }, doc => "docs-bulk", method => "POST", parts => { index => {}, type => {} }, paths => [ [ { index => 0, type => 1 }, "{index}", "{type}", "_bulk" ], [ { index => 0 }, "{index}", "_bulk" ], [ {}, "_bulk" ], ], qs => { _source => "list", _source_excludes => "list", _source_includes => "list", error_trace => "boolean", filter_path => "list", human => "boolean", pipeline => "string", refresh => "enum", require_alias => "boolean", routing => "string", timeout => "time", wait_for_active_shards => "string", }, serialize => "bulk", }, 'clear_scroll' => { body => {}, doc => "clear-scroll-api", method => "DELETE", parts => { scroll_id => { multi => 1 } }, paths => [ [ { scroll_id => 2 }, "_search", "scroll", "{scroll_id}" ], [ {}, "_search", "scroll" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'close_point_in_time' => { body => {}, doc => "point-in-time-api", method => "DELETE", parts => {}, paths => [ [ {}, "_pit" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'count' => { body => {}, doc => "search-count", method => "POST", parts => { index => { multi => 1 }, type => { multi => 1 } }, paths => [ [ { index => 0, type => 1 }, "{index}", "{type}", "_count" ], [ { index => 0 }, "{index}", "_count" ], [ {}, "_count" ], ], qs => { allow_no_indices => "boolean", analyze_wildcard => "boolean", analyzer => "string", default_operator => "enum", df => "string", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_throttled => "boolean", ignore_unavailable => "boolean", lenient => "boolean", min_score => "number", preference => "string", q => "string", routing => "list", terminate_after => "number", }, }, 'create' => { body => { required => 1 }, doc => "docs-index_", method => "PUT", parts => { id => {}, index => {}, type => {} }, paths => [ [ { id => 2, index => 0, type => 1 }, "{index}", "{type}", "{id}", "_create", ], [ { id => 2, index => 0 }, "{index}", "_create", "{id}" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", pipeline => "string", refresh => "enum", routing => "string", timeout => "time", version => "number", version_type => "enum", wait_for_active_shards => "string", }, }, 'delete' => { doc => "docs-delete", method => "DELETE", parts => { id => {}, index => {}, type => {} }, paths => [ [ { id => 2, index => 0, type => 1 }, "{index}", "{type}", "{id}" ], [ { id => 2, index => 0 }, "{index}", "_doc", "{id}" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", if_primary_term => "number", if_seq_no => "number", refresh => "enum", routing => "string", timeout => "time", version => "number", version_type => "enum", wait_for_active_shards => "string", }, }, 'delete_by_query' => { body => { required => 1 }, doc => "docs-delete-by-query", method => "POST", parts => { index => { multi => 1, required => 1 }, type => { multi => 1 } }, paths => [ [ { index => 0, type => 1 }, "{index}", "{type}", "_delete_by_query", ], [ { index => 0 }, "{index}", "_delete_by_query" ], ], qs => { _source => "list", _source_excludes => "list", _source_includes => "list", allow_no_indices => "boolean", analyze_wildcard => "boolean", analyzer => "string", conflicts => "enum", default_operator => "enum", df => "string", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", from => "number", human => "boolean", ignore_unavailable => "boolean", lenient => "boolean", max_docs => "number", preference => "string", q => "string", refresh => "boolean", request_cache => "boolean", requests_per_second => "number", routing => "list", scroll => "time", scroll_size => "number", search_timeout => "time", search_type => "enum", size => "number", slices => "number|string", sort => "list", stats => "list", terminate_after => "number", timeout => "time", version => "boolean", wait_for_active_shards => "string", wait_for_completion => "boolean", }, }, 'delete_by_query_rethrottle' => { doc => "docs-delete-by-query", method => "POST", parts => { task_id => {} }, paths => [ [ { task_id => 1 }, "_delete_by_query", "{task_id}", "_rethrottle", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", requests_per_second => "number", }, }, 'delete_script' => { doc => "modules-scripting", method => "DELETE", parts => { id => {} }, paths => [ [ { id => 1 }, "_scripts", "{id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", timeout => "time", }, }, 'exists' => { doc => "docs-get", method => "HEAD", parts => { id => {}, index => {}, type => {} }, paths => [ [ { id => 2, index => 0, type => 1 }, "{index}", "{type}", "{id}" ], [ { id => 2, index => 0 }, "{index}", "_doc", "{id}" ], ], qs => { _source => "list", _source_excludes => "list", _source_includes => "list", error_trace => "boolean", filter_path => "list", human => "boolean", preference => "string", realtime => "boolean", refresh => "boolean", routing => "string", stored_fields => "list", version => "number", version_type => "enum", }, }, 'exists_source' => { doc => "docs-get", method => "HEAD", parts => { id => {}, index => {}, type => {} }, paths => [ [ { id => 2, index => 0, type => 1 }, "{index}", "{type}", "{id}", "_source", ], [ { id => 2, index => 0 }, "{index}", "_source", "{id}" ], ], qs => { _source => "list", _source_excludes => "list", _source_includes => "list", error_trace => "boolean", filter_path => "list", human => "boolean", preference => "string", realtime => "boolean", refresh => "boolean", routing => "string", version => "number", version_type => "enum", }, }, 'explain' => { body => {}, doc => "search-explain", parts => { id => {}, index => {}, type => {} }, paths => [ [ { id => 2, index => 0, type => 1 }, "{index}", "{type}", "{id}", "_explain", ], [ { id => 2, index => 0 }, "{index}", "_explain", "{id}" ], ], qs => { _source => "list", _source_excludes => "list", _source_includes => "list", analyze_wildcard => "boolean", analyzer => "string", default_operator => "enum", df => "string", error_trace => "boolean", filter_path => "list", human => "boolean", lenient => "boolean", preference => "string", q => "string", routing => "string", stored_fields => "list", }, }, 'field_caps' => { body => {}, doc => "search-field-caps", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}", "_field_caps" ], [ {}, "_field_caps" ], ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", fields => "list", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", include_unmapped => "boolean", }, }, 'get' => { doc => "docs-get", parts => { id => {}, index => {}, type => {} }, paths => [ [ { id => 2, index => 0, type => 1 }, "{index}", "{type}", "{id}" ], [ { id => 2, index => 0 }, "{index}", "_doc", "{id}" ], ], qs => { _source => "list", _source_excludes => "list", _source_includes => "list", error_trace => "boolean", filter_path => "list", human => "boolean", preference => "string", realtime => "boolean", refresh => "boolean", routing => "string", stored_fields => "list", version => "number", version_type => "enum", }, }, 'get_script' => { doc => "modules-scripting", parts => { id => {} }, paths => [ [ { id => 1 }, "_scripts", "{id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", }, }, 'get_script_context' => { doc => "painless-contexts", parts => {}, paths => [ [ {}, "_script_context" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'get_script_languages' => { doc => "modules-scripting", parts => {}, paths => [ [ {}, "_script_language" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'get_source' => { doc => "docs-get", parts => { id => {}, index => {}, type => {} }, paths => [ [ { id => 2, index => 0, type => 1 }, "{index}", "{type}", "{id}", "_source", ], [ { id => 2, index => 0 }, "{index}", "_source", "{id}" ], ], qs => { _source => "list", _source_excludes => "list", _source_includes => "list", error_trace => "boolean", filter_path => "list", human => "boolean", preference => "string", realtime => "boolean", refresh => "boolean", routing => "string", version => "number", version_type => "enum", }, }, 'index' => { body => { required => 1 }, doc => "docs-index_", method => "POST", parts => { id => {}, index => {}, type => {} }, paths => [ [ { id => 2, index => 0, type => 1 }, "{index}", "{type}", "{id}" ], [ { id => 2, index => 0 }, "{index}", "_doc", "{id}" ], [ { index => 0, type => 1 }, "{index}", "{type}" ], [ { index => 0 }, "{index}", "_doc" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", if_primary_term => "number", if_seq_no => "number", op_type => "enum", pipeline => "string", refresh => "enum", require_alias => "boolean", routing => "string", timeout => "time", version => "number", version_type => "enum", wait_for_active_shards => "string", }, }, 'info' => { doc => "index", parts => {}, paths => [ [ {} ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'mget' => { body => { required => 1 }, doc => "docs-multi-get", parts => { index => {}, type => {} }, paths => [ [ { index => 0, type => 1 }, "{index}", "{type}", "_mget" ], [ { index => 0 }, "{index}", "_mget" ], [ {}, "_mget" ], ], qs => { _source => "list", _source_excludes => "list", _source_includes => "list", error_trace => "boolean", filter_path => "list", human => "boolean", preference => "string", realtime => "boolean", refresh => "boolean", routing => "string", stored_fields => "list", }, }, 'msearch' => { body => { required => 1 }, doc => "search-multi-search", parts => { index => { multi => 1 }, type => { multi => 1 } }, paths => [ [ { index => 0, type => 1 }, "{index}", "{type}", "_msearch" ], [ { index => 0 }, "{index}", "_msearch" ], [ {}, "_msearch" ], ], qs => { ccs_minimize_roundtrips => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", max_concurrent_searches => "number", max_concurrent_shard_requests => "number", pre_filter_shard_size => "number", rest_total_hits_as_int => "boolean", search_type => "enum", typed_keys => "boolean", }, serialize => "bulk", }, 'msearch_template' => { body => { required => 1 }, doc => "search-multi-search", parts => { index => { multi => 1 }, type => { multi => 1 } }, paths => [ [ { index => 0, type => 1 }, "{index}", "{type}", "_msearch", "template", ], [ { index => 0 }, "{index}", "_msearch", "template" ], [ {}, "_msearch", "template" ], ], qs => { ccs_minimize_roundtrips => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", max_concurrent_searches => "number", rest_total_hits_as_int => "boolean", search_type => "enum", typed_keys => "boolean", }, serialize => "bulk", }, 'mtermvectors' => { body => {}, doc => "docs-multi-termvectors", parts => { index => {}, type => {} }, paths => [ [ { index => 0, type => 1 }, "{index}", "{type}", "_mtermvectors" ], [ { index => 0 }, "{index}", "_mtermvectors" ], [ {}, "_mtermvectors" ], ], qs => { error_trace => "boolean", field_statistics => "boolean", fields => "list", filter_path => "list", human => "boolean", ids => "list", offsets => "boolean", payloads => "boolean", positions => "boolean", preference => "string", realtime => "boolean", routing => "string", term_statistics => "boolean", version => "number", version_type => "enum", }, }, 'open_point_in_time' => { doc => "point-in-time-api", method => "POST", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}", "_pit" ] ], qs => { error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", keep_alive => "string", preference => "string", routing => "string", }, }, 'ping' => { doc => "index", method => "HEAD", parts => {}, paths => [ [ {} ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'put_script' => { body => { required => 1 }, doc => "modules-scripting", method => "PUT", parts => { context => {}, id => {} }, paths => [ [ { context => 2, id => 1 }, "_scripts", "{id}", "{context}" ], [ { id => 1 }, "_scripts", "{id}" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", timeout => "time", }, }, 'rank_eval' => { body => { required => 1 }, doc => "search-rank-eval", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}", "_rank_eval" ], [ {}, "_rank_eval" ] ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", search_type => "enum", }, }, 'reindex' => { body => { required => 1 }, doc => "docs-reindex", method => "POST", parts => {}, paths => [ [ {}, "_reindex" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", max_docs => "number", refresh => "boolean", requests_per_second => "number", scroll => "time", slices => "number|string", timeout => "time", wait_for_active_shards => "string", wait_for_completion => "boolean", }, }, 'reindex_rethrottle' => { doc => "docs-reindex", method => "POST", parts => { task_id => {} }, paths => [ [ { task_id => 1 }, "_reindex", "{task_id}", "_rethrottle" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", requests_per_second => "number", }, }, 'render_search_template' => { body => {}, doc => "render-search-template-api", parts => { id => {} }, paths => [ [ { id => 2 }, "_render", "template", "{id}" ], [ {}, "_render", "template" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'scripts_painless_execute' => { body => {}, doc => "painless-execute-api", parts => {}, paths => [ [ {}, "_scripts", "painless", "_execute" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'scroll' => { body => {}, doc => "", parts => { scroll_id => {} }, paths => [ [ { scroll_id => 2 }, "_search", "scroll", "{scroll_id}" ], [ {}, "_search", "scroll" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", rest_total_hits_as_int => "boolean", scroll => "time", }, }, 'search' => { body => {}, doc => "search-search", parts => { index => { multi => 1 }, type => { multi => 1 } }, paths => [ [ { index => 0, type => 1 }, "{index}", "{type}", "_search" ], [ { index => 0 }, "{index}", "_search" ], [ {}, "_search" ], ], qs => { _source => "list", _source_excludes => "list", _source_includes => "list", allow_no_indices => "boolean", allow_partial_search_results => "boolean", analyze_wildcard => "boolean", analyzer => "string", batched_reduce_size => "number", ccs_minimize_roundtrips => "boolean", default_operator => "enum", df => "string", docvalue_fields => "list", error_trace => "boolean", expand_wildcards => "enum", explain => "boolean", filter_path => "list", from => "number", human => "boolean", ignore_throttled => "boolean", ignore_unavailable => "boolean", lenient => "boolean", max_concurrent_shard_requests => "number", min_compatible_shard_node => "string", pre_filter_shard_size => "number", preference => "string", q => "string", request_cache => "boolean", rest_total_hits_as_int => "boolean", routing => "list", scroll => "time", search_type => "enum", seq_no_primary_term => "boolean", size => "number", sort => "list", stats => "list", stored_fields => "list", suggest_field => "string", suggest_mode => "enum", suggest_size => "number", suggest_text => "string", terminate_after => "number", timeout => "time", track_scores => "boolean", track_total_hits => "boolean", typed_keys => "boolean", version => "boolean", }, }, 'search_mvt' => { body => {}, doc => "search-vector-tile-api", method => "POST", parts => { field => {}, index => { multi => 1 }, x => {}, y => {}, zoom => {} }, paths => [ [ { field => 2, index => 0, x => 4, y => 5, zoom => 3 }, "{index}", "_mvt", "{field}", "{zoom}", "{x}", "{y}", ], ], qs => { error_trace => "boolean", exact_bounds => "boolean", extent => "int", filter_path => "list", grid_precision => "int", grid_type => "enum", human => "boolean", size => "int", }, }, 'search_shards' => { doc => "search-shards", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}", "_search_shards" ], [ {}, "_search_shards" ], ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", local => "boolean", preference => "string", routing => "string", }, }, 'search_template' => { body => { required => 1 }, doc => "search-template", parts => { index => { multi => 1 }, type => { multi => 1 } }, paths => [ [ { index => 0, type => 1 }, "{index}", "{type}", "_search", "template", ], [ { index => 0 }, "{index}", "_search", "template" ], [ {}, "_search", "template" ], ], qs => { allow_no_indices => "boolean", ccs_minimize_roundtrips => "boolean", error_trace => "boolean", expand_wildcards => "enum", explain => "boolean", filter_path => "list", human => "boolean", ignore_throttled => "boolean", ignore_unavailable => "boolean", preference => "string", profile => "boolean", rest_total_hits_as_int => "boolean", routing => "list", scroll => "time", search_type => "enum", typed_keys => "boolean", }, }, 'terms_enum' => { body => {}, doc => "search-terms-enum", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}", "_terms_enum" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'termvectors' => { body => {}, doc => "docs-termvectors", parts => { id => {}, index => { required => 1 }, type => {} }, paths => [ [ { id => 2, index => 0, type => 1 }, "{index}", "{type}", "{id}", "_termvectors", ], [ { id => 2, index => 0 }, "{index}", "_termvectors", "{id}" ], [ { index => 0, type => 1 }, "{index}", "{type}", "_termvectors" ], [ { index => 0 }, "{index}", "_termvectors" ], ], qs => { error_trace => "boolean", field_statistics => "boolean", fields => "list", filter_path => "list", human => "boolean", offsets => "boolean", payloads => "boolean", positions => "boolean", preference => "string", realtime => "boolean", routing => "string", term_statistics => "boolean", version => "number", version_type => "enum", }, }, 'update' => { body => { required => 1 }, doc => "docs-update", method => "POST", parts => { id => {}, index => {}, type => {} }, paths => [ [ { id => 2, index => 0, type => 1 }, "{index}", "{type}", "{id}", "_update", ], [ { id => 2, index => 0 }, "{index}", "_update", "{id}" ], ], qs => { _source => "list", _source_excludes => "list", _source_includes => "list", error_trace => "boolean", filter_path => "list", human => "boolean", if_primary_term => "number", if_seq_no => "number", lang => "string", refresh => "enum", require_alias => "boolean", retry_on_conflict => "number", routing => "string", timeout => "time", wait_for_active_shards => "string", }, }, 'update_by_query' => { body => {}, doc => "docs-update-by-query", method => "POST", parts => { index => { multi => 1, required => 1 }, type => { multi => 1 } }, paths => [ [ { index => 0, type => 1 }, "{index}", "{type}", "_update_by_query", ], [ { index => 0 }, "{index}", "_update_by_query" ], ], qs => { _source => "list", _source_excludes => "list", _source_includes => "list", allow_no_indices => "boolean", analyze_wildcard => "boolean", analyzer => "string", conflicts => "enum", default_operator => "enum", df => "string", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", from => "number", human => "boolean", ignore_unavailable => "boolean", lenient => "boolean", max_docs => "number", pipeline => "string", preference => "string", q => "string", refresh => "boolean", request_cache => "boolean", requests_per_second => "number", routing => "list", scroll => "time", scroll_size => "number", search_timeout => "time", search_type => "enum", size => "number", slices => "number|string", sort => "list", stats => "list", terminate_after => "number", timeout => "time", version => "boolean", version_type => "boolean", wait_for_active_shards => "string", wait_for_completion => "boolean", }, }, 'update_by_query_rethrottle' => { doc => "docs-update-by-query", method => "POST", parts => { task_id => {} }, paths => [ [ { task_id => 1 }, "_update_by_query", "{task_id}", "_rethrottle", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", requests_per_second => "number", }, }, 'async_search.delete' => { doc => "async-search", method => "DELETE", parts => { id => {} }, paths => [ [ { id => 1 }, "_async_search", "{id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'async_search.get' => { doc => "async-search", parts => { id => {} }, paths => [ [ { id => 1 }, "_async_search", "{id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", keep_alive => "time", typed_keys => "boolean", wait_for_completion_timeout => "time", }, }, 'async_search.status' => { doc => "async-search", parts => { id => {} }, paths => [ [ { id => 2 }, "_async_search", "status", "{id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'async_search.submit' => { body => {}, doc => "async-search", method => "POST", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}", "_async_search" ], [ {}, "_async_search" ], ], qs => { _source => "list", _source_excludes => "list", _source_includes => "list", allow_no_indices => "boolean", allow_partial_search_results => "boolean", analyze_wildcard => "boolean", analyzer => "string", batched_reduce_size => "number", default_operator => "enum", df => "string", docvalue_fields => "list", error_trace => "boolean", expand_wildcards => "enum", explain => "boolean", filter_path => "list", from => "number", human => "boolean", ignore_throttled => "boolean", ignore_unavailable => "boolean", keep_alive => "time", keep_on_completion => "boolean", lenient => "boolean", max_concurrent_shard_requests => "number", preference => "string", q => "string", request_cache => "boolean", routing => "list", search_type => "enum", seq_no_primary_term => "boolean", size => "number", sort => "list", stats => "list", stored_fields => "list", suggest_field => "string", suggest_mode => "enum", suggest_size => "number", suggest_text => "string", terminate_after => "number", timeout => "time", track_scores => "boolean", track_total_hits => "boolean", typed_keys => "boolean", version => "boolean", wait_for_completion_timeout => "time", }, }, 'autoscaling.delete_autoscaling_policy' => { doc => "autoscaling-delete-autoscaling-policy", method => "DELETE", parts => { name => {} }, paths => [ [ { name => 2 }, "_autoscaling", "policy", "{name}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'autoscaling.get_autoscaling_capacity' => { doc => "autoscaling-get-autoscaling-capacity", parts => {}, paths => [ [ {}, "_autoscaling", "capacity" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'autoscaling.get_autoscaling_policy' => { doc => "autoscaling-get-autoscaling-policy", parts => { name => {} }, paths => [ [ { name => 2 }, "_autoscaling", "policy", "{name}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'autoscaling.put_autoscaling_policy' => { body => { required => 1 }, doc => "autoscaling-put-autoscaling-policy", method => "PUT", parts => { name => {} }, paths => [ [ { name => 2 }, "_autoscaling", "policy", "{name}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'cat.aliases' => { doc => "cat-alias", parts => { name => { multi => 1 } }, paths => [ [ { name => 2 }, "_cat", "aliases", "{name}" ], [ {}, "_cat", "aliases" ], ], qs => { error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", format => "string", h => "list", help => "boolean", human => "boolean", local => "boolean", s => "list", v => "boolean", }, }, 'cat.allocation' => { doc => "cat-allocation", parts => { node_id => { multi => 1 } }, paths => [ [ { node_id => 2 }, "_cat", "allocation", "{node_id}" ], [ {}, "_cat", "allocation" ], ], qs => { bytes => "enum", error_trace => "boolean", filter_path => "list", format => "string", h => "list", help => "boolean", human => "boolean", local => "boolean", master_timeout => "time", s => "list", v => "boolean", }, }, 'cat.count' => { doc => "cat-count", parts => { index => { multi => 1 } }, paths => [ [ { index => 2 }, "_cat", "count", "{index}" ], [ {}, "_cat", "count" ], ], qs => { error_trace => "boolean", filter_path => "list", format => "string", h => "list", help => "boolean", human => "boolean", s => "list", v => "boolean", }, }, 'cat.fielddata' => { doc => "cat-fielddata", parts => { fields => { multi => 1 } }, paths => [ [ { fields => 2 }, "_cat", "fielddata", "{fields}" ], [ {}, "_cat", "fielddata" ], ], qs => { bytes => "enum", error_trace => "boolean", filter_path => "list", format => "string", h => "list", help => "boolean", human => "boolean", s => "list", v => "boolean", }, }, 'cat.health' => { doc => "cat-health", parts => {}, paths => [ [ {}, "_cat", "health" ] ], qs => { error_trace => "boolean", filter_path => "list", format => "string", h => "list", help => "boolean", human => "boolean", s => "list", time => "enum", ts => "boolean", v => "boolean", }, }, 'cat.help' => { doc => "cat", parts => {}, paths => [ [ {}, "_cat" ] ], qs => { error_trace => "boolean", filter_path => "list", help => "boolean", human => "boolean", s => "list", }, }, 'cat.indices' => { doc => "cat-indices", parts => { index => { multi => 1 } }, paths => [ [ { index => 2 }, "_cat", "indices", "{index}" ], [ {}, "_cat", "indices" ], ], qs => { bytes => "enum", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", format => "string", h => "list", health => "enum", help => "boolean", human => "boolean", include_unloaded_segments => "boolean", local => "boolean", master_timeout => "time", pri => "boolean", s => "list", time => "enum", v => "boolean", }, }, 'cat.master' => { doc => "cat-master", parts => {}, paths => [ [ {}, "_cat", "master" ] ], qs => { error_trace => "boolean", filter_path => "list", format => "string", h => "list", help => "boolean", human => "boolean", local => "boolean", master_timeout => "time", s => "list", v => "boolean", }, }, 'cat.ml_data_frame_analytics' => { doc => "cat-dfanalytics", parts => { id => {} }, paths => [ [ { id => 4 }, "_cat", "ml", "data_frame", "analytics", "{id}" ], [ {}, "_cat", "ml", "data_frame", "analytics" ], ], qs => { allow_no_match => "boolean", bytes => "enum", error_trace => "boolean", filter_path => "list", format => "string", h => "list", help => "boolean", human => "boolean", s => "list", time => "enum", v => "boolean", }, }, 'cat.ml_datafeeds' => { doc => "cat-datafeeds", parts => { datafeed_id => {} }, paths => [ [ { datafeed_id => 3 }, "_cat", "ml", "datafeeds", "{datafeed_id}" ], [ {}, "_cat", "ml", "datafeeds" ], ], qs => { allow_no_datafeeds => "boolean", allow_no_match => "boolean", error_trace => "boolean", filter_path => "list", format => "string", h => "list", help => "boolean", human => "boolean", s => "list", time => "enum", v => "boolean", }, }, 'cat.ml_jobs' => { doc => "cat-anomaly-detectors", parts => { job_id => {} }, paths => [ [ { job_id => 3 }, "_cat", "ml", "anomaly_detectors", "{job_id}" ], [ {}, "_cat", "ml", "anomaly_detectors" ], ], qs => { allow_no_jobs => "boolean", allow_no_match => "boolean", bytes => "enum", error_trace => "boolean", filter_path => "list", format => "string", h => "list", help => "boolean", human => "boolean", s => "list", time => "enum", v => "boolean", }, }, 'cat.ml_trained_models' => { doc => "cat-trained-model", parts => { model_id => {} }, paths => [ [ { model_id => 3 }, "_cat", "ml", "trained_models", "{model_id}" ], [ {}, "_cat", "ml", "trained_models" ], ], qs => { allow_no_match => "boolean", bytes => "enum", error_trace => "boolean", filter_path => "list", format => "string", from => "int", h => "list", help => "boolean", human => "boolean", s => "list", size => "int", time => "enum", v => "boolean", }, }, 'cat.nodeattrs' => { doc => "cat-nodeattrs", parts => {}, paths => [ [ {}, "_cat", "nodeattrs" ] ], qs => { error_trace => "boolean", filter_path => "list", format => "string", h => "list", help => "boolean", human => "boolean", local => "boolean", master_timeout => "time", s => "list", v => "boolean", }, }, 'cat.nodes' => { doc => "cat-nodes", parts => {}, paths => [ [ {}, "_cat", "nodes" ] ], qs => { bytes => "enum", error_trace => "boolean", filter_path => "list", format => "string", full_id => "boolean", h => "list", help => "boolean", human => "boolean", include_unloaded_segments => "boolean", local => "boolean", master_timeout => "time", s => "list", time => "enum", v => "boolean", }, }, 'cat.pending_tasks' => { doc => "cat-pending-tasks", parts => {}, paths => [ [ {}, "_cat", "pending_tasks" ] ], qs => { error_trace => "boolean", filter_path => "list", format => "string", h => "list", help => "boolean", human => "boolean", local => "boolean", master_timeout => "time", s => "list", time => "enum", v => "boolean", }, }, 'cat.plugins' => { doc => "cat-plugins", parts => {}, paths => [ [ {}, "_cat", "plugins" ] ], qs => { error_trace => "boolean", filter_path => "list", format => "string", h => "list", help => "boolean", human => "boolean", include_bootstrap => "boolean", local => "boolean", master_timeout => "time", s => "list", v => "boolean", }, }, 'cat.recovery' => { doc => "cat-recovery", parts => { index => { multi => 1 } }, paths => [ [ { index => 2 }, "_cat", "recovery", "{index}" ], [ {}, "_cat", "recovery" ], ], qs => { active_only => "boolean", bytes => "enum", detailed => "boolean", error_trace => "boolean", filter_path => "list", format => "string", h => "list", help => "boolean", human => "boolean", s => "list", time => "enum", v => "boolean", }, }, 'cat.repositories' => { doc => "cat-repositories", parts => {}, paths => [ [ {}, "_cat", "repositories" ] ], qs => { error_trace => "boolean", filter_path => "list", format => "string", h => "list", help => "boolean", human => "boolean", local => "boolean", master_timeout => "time", s => "list", v => "boolean", }, }, 'cat.segments' => { doc => "cat-segments", parts => { index => { multi => 1 } }, paths => [ [ { index => 2 }, "_cat", "segments", "{index}" ], [ {}, "_cat", "segments" ], ], qs => { bytes => "enum", error_trace => "boolean", filter_path => "list", format => "string", h => "list", help => "boolean", human => "boolean", s => "list", v => "boolean", }, }, 'cat.shards' => { doc => "cat-shards", parts => { index => { multi => 1 } }, paths => [ [ { index => 2 }, "_cat", "shards", "{index}" ], [ {}, "_cat", "shards" ], ], qs => { bytes => "enum", error_trace => "boolean", filter_path => "list", format => "string", h => "list", help => "boolean", human => "boolean", local => "boolean", master_timeout => "time", s => "list", time => "enum", v => "boolean", }, }, 'cat.snapshots' => { doc => "cat-snapshots", parts => { repository => { multi => 1 } }, paths => [ [ { repository => 2 }, "_cat", "snapshots", "{repository}" ], [ {}, "_cat", "snapshots" ], ], qs => { error_trace => "boolean", filter_path => "list", format => "string", h => "list", help => "boolean", human => "boolean", ignore_unavailable => "boolean", master_timeout => "time", s => "list", time => "enum", v => "boolean", }, }, 'cat.tasks' => { doc => "tasks", parts => {}, paths => [ [ {}, "_cat", "tasks" ] ], qs => { actions => "list", detailed => "boolean", error_trace => "boolean", filter_path => "list", format => "string", h => "list", help => "boolean", human => "boolean", nodes => "list", parent_task_id => "string", s => "list", time => "enum", v => "boolean", }, }, 'cat.templates' => { doc => "cat-templates", parts => { name => {} }, paths => [ [ { name => 2 }, "_cat", "templates", "{name}" ], [ {}, "_cat", "templates" ], ], qs => { error_trace => "boolean", filter_path => "list", format => "string", h => "list", help => "boolean", human => "boolean", local => "boolean", master_timeout => "time", s => "list", v => "boolean", }, }, 'cat.thread_pool' => { doc => "cat-thread-pool", parts => { thread_pool_patterns => { multi => 1 } }, paths => [ [ { thread_pool_patterns => 2 }, "_cat", "thread_pool", "{thread_pool_patterns}", ], [ {}, "_cat", "thread_pool" ], ], qs => { error_trace => "boolean", filter_path => "list", format => "string", h => "list", help => "boolean", human => "boolean", local => "boolean", master_timeout => "time", s => "list", size => "enum", v => "boolean", }, }, 'cat.transforms' => { doc => "cat-transforms", parts => { transform_id => {} }, paths => [ [ { transform_id => 2 }, "_cat", "transforms", "{transform_id}" ], [ {}, "_cat", "transforms" ], ], qs => { allow_no_match => "boolean", error_trace => "boolean", filter_path => "list", format => "string", from => "int", h => "list", help => "boolean", human => "boolean", s => "list", size => "int", time => "enum", v => "boolean", }, }, 'ccr.delete_auto_follow_pattern' => { doc => "ccr-delete-auto-follow-pattern", method => "DELETE", parts => { name => {} }, paths => [ [ { name => 2 }, "_ccr", "auto_follow", "{name}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ccr.follow' => { body => { required => 1 }, doc => "ccr-put-follow", method => "PUT", parts => { index => {} }, paths => [ [ { index => 0 }, "{index}", "_ccr", "follow" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", wait_for_active_shards => "string", }, }, 'ccr.follow_info' => { doc => "ccr-get-follow-info", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}", "_ccr", "info" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ccr.follow_stats' => { doc => "ccr-get-follow-stats", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}", "_ccr", "stats" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ccr.forget_follower' => { body => { required => 1 }, doc => "ccr-post-forget-follower", method => "POST", parts => { index => {} }, paths => [ [ { index => 0 }, "{index}", "_ccr", "forget_follower" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ccr.get_auto_follow_pattern' => { doc => "ccr-get-auto-follow-pattern", parts => { name => {} }, paths => [ [ { name => 2 }, "_ccr", "auto_follow", "{name}" ], [ {}, "_ccr", "auto_follow" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ccr.pause_auto_follow_pattern' => { doc => "ccr-pause-auto-follow-pattern", method => "POST", parts => { name => {} }, paths => [ [ { name => 2 }, "_ccr", "auto_follow", "{name}", "pause" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ccr.pause_follow' => { doc => "ccr-post-pause-follow", method => "POST", parts => { index => {} }, paths => [ [ { index => 0 }, "{index}", "_ccr", "pause_follow" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ccr.put_auto_follow_pattern' => { body => { required => 1 }, doc => "ccr-put-auto-follow-pattern", method => "PUT", parts => { name => {} }, paths => [ [ { name => 2 }, "_ccr", "auto_follow", "{name}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ccr.resume_auto_follow_pattern' => { doc => "ccr-resume-auto-follow-pattern", method => "POST", parts => { name => {} }, paths => [ [ { name => 2 }, "_ccr", "auto_follow", "{name}", "resume" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ccr.resume_follow' => { body => {}, doc => "ccr-post-resume-follow", method => "POST", parts => { index => {} }, paths => [ [ { index => 0 }, "{index}", "_ccr", "resume_follow" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ccr.stats' => { doc => "ccr-get-stats", parts => {}, paths => [ [ {}, "_ccr", "stats" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ccr.unfollow' => { doc => "ccr-post-unfollow", method => "POST", parts => { index => {} }, paths => [ [ { index => 0 }, "{index}", "_ccr", "unfollow" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'cluster.allocation_explain' => { body => {}, doc => "cluster-allocation-explain", parts => {}, paths => [ [ {}, "_cluster", "allocation", "explain" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", include_disk_info => "boolean", include_yes_decisions => "boolean", }, }, 'cluster.delete_component_template' => { doc => "indices-component-template", method => "DELETE", parts => { name => {} }, paths => [ [ { name => 1 }, "_component_template", "{name}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", timeout => "time", }, }, 'cluster.delete_voting_config_exclusions' => { doc => "voting-config-exclusions", method => "DELETE", parts => {}, paths => [ [ {}, "_cluster", "voting_config_exclusions" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", wait_for_removal => "boolean", }, }, 'cluster.exists_component_template' => { doc => "indices-component-template", method => "HEAD", parts => { name => {} }, paths => [ [ { name => 1 }, "_component_template", "{name}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", local => "boolean", master_timeout => "time", }, }, 'cluster.get_component_template' => { doc => "indices-component-template", parts => { name => { multi => 1 } }, paths => [ [ { name => 1 }, "_component_template", "{name}" ], [ {}, "_component_template" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", local => "boolean", master_timeout => "time", }, }, 'cluster.get_settings' => { doc => "cluster-get-settings", parts => {}, paths => [ [ {}, "_cluster", "settings" ] ], qs => { error_trace => "boolean", filter_path => "list", flat_settings => "boolean", human => "boolean", include_defaults => "boolean", master_timeout => "time", timeout => "time", }, }, 'cluster.health' => { doc => "cluster-health", parts => { index => { multi => 1 } }, paths => [ [ { index => 2 }, "_cluster", "health", "{index}" ], [ {}, "_cluster", "health" ], ], qs => { error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", level => "enum", local => "boolean", master_timeout => "time", timeout => "time", wait_for_active_shards => "string", wait_for_events => "enum", wait_for_no_initializing_shards => "boolean", wait_for_no_relocating_shards => "boolean", wait_for_nodes => "string", wait_for_status => "enum", }, }, 'cluster.pending_tasks' => { doc => "cluster-pending", parts => {}, paths => [ [ {}, "_cluster", "pending_tasks" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", local => "boolean", master_timeout => "time", }, }, 'cluster.post_voting_config_exclusions' => { doc => "voting-config-exclusions", method => "POST", parts => {}, paths => [ [ {}, "_cluster", "voting_config_exclusions" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", node_ids => "string", node_names => "string", timeout => "time", }, }, 'cluster.put_component_template' => { body => { required => 1 }, doc => "indices-component-template", method => "PUT", parts => { name => {} }, paths => [ [ { name => 1 }, "_component_template", "{name}" ] ], qs => { create => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", timeout => "time", }, }, 'cluster.put_settings' => { body => { required => 1 }, doc => "cluster-update-settings", method => "PUT", parts => {}, paths => [ [ {}, "_cluster", "settings" ] ], qs => { error_trace => "boolean", filter_path => "list", flat_settings => "boolean", human => "boolean", master_timeout => "time", timeout => "time", }, }, 'cluster.remote_info' => { doc => "cluster-remote-info", parts => {}, paths => [ [ {}, "_remote", "info" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'cluster.reroute' => { body => {}, doc => "cluster-reroute", method => "POST", parts => {}, paths => [ [ {}, "_cluster", "reroute" ] ], qs => { dry_run => "boolean", error_trace => "boolean", explain => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", metric => "list", retry_failed => "boolean", timeout => "time", }, }, 'cluster.state' => { doc => "cluster-state", parts => { index => { multi => 1 }, metric => { multi => 1 } }, paths => [ [ { index => 3, metric => 2 }, "_cluster", "state", "{metric}", "{index}", ], [ { metric => 2 }, "_cluster", "state", "{metric}" ], [ {}, "_cluster", "state" ], ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", flat_settings => "boolean", human => "boolean", ignore_unavailable => "boolean", local => "boolean", master_timeout => "time", wait_for_metadata_version => "number", wait_for_timeout => "time", }, }, 'cluster.stats' => { doc => "cluster-stats", parts => { node_id => { multi => 1 } }, paths => [ [ { node_id => 3 }, "_cluster", "stats", "nodes", "{node_id}" ], [ {}, "_cluster", "stats" ], ], qs => { error_trace => "boolean", filter_path => "list", flat_settings => "boolean", human => "boolean", timeout => "time", }, }, 'dangling_indices.delete_dangling_index' => { doc => "modules-gateway-dangling-indices", method => "DELETE", parts => { index_uuid => {} }, paths => [ [ { index_uuid => 1 }, "_dangling", "{index_uuid}" ] ], qs => { accept_data_loss => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", timeout => "time", }, }, 'dangling_indices.import_dangling_index' => { doc => "modules-gateway-dangling-indices", method => "POST", parts => { index_uuid => {} }, paths => [ [ { index_uuid => 1 }, "_dangling", "{index_uuid}" ] ], qs => { accept_data_loss => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", timeout => "time", }, }, 'dangling_indices.list_dangling_indices' => { doc => "modules-gateway-dangling-indices", parts => {}, paths => [ [ {}, "_dangling" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'data_frame_transform_deprecated.delete_transform' => { doc => "delete-transform", method => "DELETE", parts => { transform_id => {} }, paths => [ [ { transform_id => 2 }, "_data_frame", "transforms", "{transform_id}", ], ], qs => { error_trace => "boolean", filter_path => "list", force => "boolean", human => "boolean", }, }, 'data_frame_transform_deprecated.get_transform' => { doc => "get-transform", parts => { transform_id => {} }, paths => [ [ { transform_id => 2 }, "_data_frame", "transforms", "{transform_id}", ], [ {}, "_data_frame", "transforms" ], ], qs => { allow_no_match => "boolean", error_trace => "boolean", exclude_generated => "boolean", filter_path => "list", from => "int", human => "boolean", size => "int", }, }, 'data_frame_transform_deprecated.get_transform_stats' => { doc => "get-transform-stats", parts => { transform_id => {} }, paths => [ [ { transform_id => 2 }, "_data_frame", "transforms", "{transform_id}", "_stats", ], ], qs => { allow_no_match => "boolean", error_trace => "boolean", filter_path => "list", from => "number", human => "boolean", size => "number", }, }, 'data_frame_transform_deprecated.preview_transform' => { body => { required => 1 }, doc => "preview-transform", method => "POST", parts => {}, paths => [ [ {}, "_data_frame", "transforms", "_preview" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'data_frame_transform_deprecated.put_transform' => { body => { required => 1 }, doc => "put-transform", method => "PUT", parts => { transform_id => {} }, paths => [ [ { transform_id => 2 }, "_data_frame", "transforms", "{transform_id}", ], ], qs => { defer_validation => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", }, }, 'data_frame_transform_deprecated.start_transform' => { doc => "start-transform", method => "POST", parts => { transform_id => {} }, paths => [ [ { transform_id => 2 }, "_data_frame", "transforms", "{transform_id}", "_start", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", timeout => "time", }, }, 'data_frame_transform_deprecated.stop_transform' => { doc => "stop-transform", method => "POST", parts => { transform_id => {} }, paths => [ [ { transform_id => 2 }, "_data_frame", "transforms", "{transform_id}", "_stop", ], ], qs => { allow_no_match => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", timeout => "time", wait_for_completion => "boolean", }, }, 'data_frame_transform_deprecated.update_transform' => { body => { required => 1 }, doc => "update-transform", method => "POST", parts => { transform_id => { required => 1 } }, paths => [ [ { transform_id => 2 }, "_data_frame", "transforms", "{transform_id}", "_update", ], ], qs => { defer_validation => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", }, }, 'enrich.delete_policy' => { doc => "delete-enrich-policy-api", method => "DELETE", parts => { name => {} }, paths => [ [ { name => 2 }, "_enrich", "policy", "{name}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'enrich.execute_policy' => { doc => "execute-enrich-policy-api", method => "PUT", parts => { name => {} }, paths => [ [ { name => 2 }, "_enrich", "policy", "{name}", "_execute" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", wait_for_completion => "boolean", }, }, 'enrich.get_policy' => { doc => "get-enrich-policy-api", parts => { name => { multi => 1 } }, paths => [ [ { name => 2 }, "_enrich", "policy", "{name}" ], [ {}, "_enrich", "policy" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'enrich.put_policy' => { body => { required => 1 }, doc => "put-enrich-policy-api", method => "PUT", parts => { name => {} }, paths => [ [ { name => 2 }, "_enrich", "policy", "{name}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'enrich.stats' => { doc => "enrich-stats-api", parts => {}, paths => [ [ {}, "_enrich", "_stats" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'eql.delete' => { doc => "eql-search-api", method => "DELETE", parts => { id => {} }, paths => [ [ { id => 2 }, "_eql", "search", "{id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'eql.get' => { doc => "eql-search-api", parts => { id => {} }, paths => [ [ { id => 2 }, "_eql", "search", "{id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", keep_alive => "time", wait_for_completion_timeout => "time", }, }, 'eql.get_status' => { doc => "eql-search-api", parts => { id => {} }, paths => [ [ { id => 3 }, "_eql", "search", "status", "{id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'eql.search' => { body => { required => 1 }, doc => "eql-search-api", parts => { index => {} }, paths => [ [ { index => 0 }, "{index}", "_eql", "search" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", keep_alive => "time", keep_on_completion => "boolean", wait_for_completion_timeout => "time", }, }, 'features.get_features' => { doc => "get-features-api", parts => {}, paths => [ [ {}, "_features" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", }, }, 'features.reset_features' => { doc => "modules-snapshots", method => "POST", parts => {}, paths => [ [ {}, "_features", "_reset" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'fleet.global_checkpoints' => { parts => { index => {} }, paths => [ [ { index => 0 }, "{index}", "_fleet", "global_checkpoints" ] ], qs => { checkpoints => "list", error_trace => "boolean", filter_path => "list", human => "boolean", timeout => "time", wait_for_advance => "boolean", wait_for_index => "boolean", }, }, 'graph.explore' => { body => {}, doc => "graph-explore-api", parts => { index => { multi => 1 }, type => { multi => 1 } }, paths => [ [ { index => 0, type => 1 }, "{index}", "{type}", "_graph", "explore", ], [ { index => 0 }, "{index}", "_graph", "explore" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", routing => "string", timeout => "time", }, }, 'ilm.delete_lifecycle' => { doc => "ilm-delete-lifecycle", method => "DELETE", parts => { policy => {} }, paths => [ [ { policy => 2 }, "_ilm", "policy", "{policy}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ilm.explain_lifecycle' => { doc => "ilm-explain-lifecycle", parts => { index => {} }, paths => [ [ { index => 0 }, "{index}", "_ilm", "explain" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", only_errors => "boolean", only_managed => "boolean", }, }, 'ilm.get_lifecycle' => { doc => "ilm-get-lifecycle", parts => { policy => {} }, paths => [ [ { policy => 2 }, "_ilm", "policy", "{policy}" ], [ {}, "_ilm", "policy" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ilm.get_status' => { doc => "ilm-get-status", parts => {}, paths => [ [ {}, "_ilm", "status" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ilm.migrate_to_data_tiers' => { body => {}, doc => "ilm-migrate-to-data-tiers", method => "POST", parts => {}, paths => [ [ {}, "_ilm", "migrate_to_data_tiers" ] ], qs => { dry_run => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", }, }, 'ilm.move_to_step' => { body => {}, doc => "ilm-move-to-step", method => "POST", parts => { index => {} }, paths => [ [ { index => 2 }, "_ilm", "move", "{index}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ilm.put_lifecycle' => { body => {}, doc => "ilm-put-lifecycle", method => "PUT", parts => { policy => {} }, paths => [ [ { policy => 2 }, "_ilm", "policy", "{policy}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ilm.remove_policy' => { doc => "ilm-remove-policy", method => "POST", parts => { index => {} }, paths => [ [ { index => 0 }, "{index}", "_ilm", "remove" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ilm.retry' => { doc => "ilm-retry-policy", method => "POST", parts => { index => {} }, paths => [ [ { index => 0 }, "{index}", "_ilm", "retry" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ilm.start' => { doc => "ilm-start", method => "POST", parts => {}, paths => [ [ {}, "_ilm", "start" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ilm.stop' => { doc => "ilm-stop", method => "POST", parts => {}, paths => [ [ {}, "_ilm", "stop" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'indices.add_block' => { doc => "index-modules-blocks", method => "PUT", parts => { block => {}, index => { multi => 1 } }, paths => [ [ { block => 2, index => 0 }, "{index}", "_block", "{block}" ] ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", master_timeout => "time", timeout => "time", }, }, 'indices.analyze' => { body => {}, doc => "indices-analyze", parts => { index => {} }, paths => [ [ { index => 0 }, "{index}", "_analyze" ], [ {}, "_analyze" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'indices.clear_cache' => { doc => "indices-clearcache", method => "POST", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}", "_cache", "clear" ], [ {}, "_cache", "clear" ], ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", fielddata => "boolean", fields => "list", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", query => "boolean", request => "boolean", }, }, 'indices.clone' => { body => {}, doc => "indices-clone-index", method => "PUT", parts => { index => {}, target => {} }, paths => [ [ { index => 0, target => 2 }, "{index}", "_clone", "{target}" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", timeout => "time", wait_for_active_shards => "string", }, }, 'indices.close' => { doc => "indices-open-close", method => "POST", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}", "_close" ] ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", master_timeout => "time", timeout => "time", wait_for_active_shards => "string", }, }, 'indices.create' => { body => {}, doc => "indices-create-index", method => "PUT", parts => { index => {} }, paths => [ [ { index => 0 }, "{index}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", include_type_name => "boolean", master_timeout => "time", timeout => "time", wait_for_active_shards => "string", }, }, 'indices.create_data_stream' => { doc => "data-streams", method => "PUT", parts => { name => {} }, paths => [ [ { name => 1 }, "_data_stream", "{name}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'indices.data_streams_stats' => { doc => "data-streams", parts => { name => { multi => 1 } }, paths => [ [ { name => 1 }, "_data_stream", "{name}", "_stats" ], [ {}, "_data_stream", "_stats" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'indices.delete' => { doc => "indices-delete-index", method => "DELETE", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}" ] ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", master_timeout => "time", timeout => "time", }, }, 'indices.delete_alias' => { doc => "indices-aliases", method => "DELETE", parts => { index => { multi => 1 }, name => { multi => 1 } }, paths => [ [ { index => 0, name => 2 }, "{index}", "_alias", "{name}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", timeout => "time", }, }, 'indices.delete_data_stream' => { doc => "data-streams", method => "DELETE", parts => { name => { multi => 1 } }, paths => [ [ { name => 1 }, "_data_stream", "{name}" ] ], qs => { error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", }, }, 'indices.delete_index_template' => { doc => "indices-templates", method => "DELETE", parts => { name => {} }, paths => [ [ { name => 1 }, "_index_template", "{name}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", timeout => "time", }, }, 'indices.delete_template' => { doc => "indices-templates", method => "DELETE", parts => { name => {} }, paths => [ [ { name => 1 }, "_template", "{name}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", timeout => "time", }, }, 'indices.disk_usage' => { doc => "indices-disk-usage", method => "POST", parts => { index => {} }, paths => [ [ { index => 0 }, "{index}", "_disk_usage" ] ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", flush => "boolean", human => "boolean", ignore_unavailable => "boolean", run_expensive_tasks => "boolean", }, }, 'indices.exists' => { doc => "indices-exists", method => "HEAD", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}" ] ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", flat_settings => "boolean", human => "boolean", ignore_unavailable => "boolean", include_defaults => "boolean", local => "boolean", }, }, 'indices.exists_alias' => { doc => "indices-aliases", method => "HEAD", parts => { index => { multi => 1 }, name => { multi => 1 } }, paths => [ [ { index => 0, name => 2 }, "{index}", "_alias", "{name}" ], [ { name => 1 }, "_alias", "{name}" ], ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", local => "boolean", }, }, 'indices.exists_index_template' => { doc => "indices-templates", method => "HEAD", parts => { name => {} }, paths => [ [ { name => 1 }, "_index_template", "{name}" ] ], qs => { error_trace => "boolean", filter_path => "list", flat_settings => "boolean", human => "boolean", local => "boolean", master_timeout => "time", }, }, 'indices.exists_template' => { doc => "indices-templates", method => "HEAD", parts => { name => { multi => 1 } }, paths => [ [ { name => 1 }, "_template", "{name}" ] ], qs => { error_trace => "boolean", filter_path => "list", flat_settings => "boolean", human => "boolean", local => "boolean", master_timeout => "time", }, }, 'indices.exists_type' => { doc => "indices-types-exists", method => "HEAD", parts => { index => { multi => 1 }, type => { multi => 1 } }, paths => [ [ { index => 0, type => 2 }, "{index}", "_mapping", "{type}" ] ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", local => "boolean", }, }, 'indices.field_usage_stats' => { doc => "field-usage-stats", parts => { index => {} }, paths => [ [ { index => 0 }, "{index}", "_field_usage_stats" ] ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", fields => "list", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", }, }, 'indices.flush' => { doc => "indices-flush", method => "POST", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}", "_flush" ], [ {}, "_flush" ] ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", force => "boolean", human => "boolean", ignore_unavailable => "boolean", wait_if_ongoing => "boolean", }, }, 'indices.flush_synced' => { doc => "indices-synced-flush-api", method => "POST", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}", "_flush", "synced" ], [ {}, "_flush", "synced" ], ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", }, }, 'indices.forcemerge' => { doc => "indices-forcemerge", method => "POST", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}", "_forcemerge" ], [ {}, "_forcemerge" ], ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", flush => "boolean", human => "boolean", ignore_unavailable => "boolean", max_num_segments => "number", only_expunge_deletes => "boolean", }, }, 'indices.freeze' => { doc => "freeze-index-api", method => "POST", parts => { index => {} }, paths => [ [ { index => 0 }, "{index}", "_freeze" ] ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", master_timeout => "time", timeout => "time", wait_for_active_shards => "string", }, }, 'indices.get' => { doc => "indices-get-index", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}" ] ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", flat_settings => "boolean", human => "boolean", ignore_unavailable => "boolean", include_defaults => "boolean", include_type_name => "boolean", local => "boolean", master_timeout => "time", }, }, 'indices.get_alias' => { doc => "indices-aliases", parts => { index => { multi => 1 }, name => { multi => 1 } }, paths => [ [ { index => 0, name => 2 }, "{index}", "_alias", "{name}" ], [ { index => 0 }, "{index}", "_alias" ], [ { name => 1 }, "_alias", "{name}" ], [ {}, "_alias" ], ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", local => "boolean", }, }, 'indices.get_data_stream' => { doc => "data-streams", parts => { name => { multi => 1 } }, paths => [ [ { name => 1 }, "_data_stream", "{name}" ], [ {}, "_data_stream" ], ], qs => { error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", }, }, 'indices.get_field_mapping' => { doc => "indices-get-field-mapping", parts => { fields => { multi => 1 }, index => { multi => 1 }, type => { multi => 1 }, }, paths => [ [ { fields => 4, index => 0, type => 2 }, "{index}", "_mapping", "{type}", "field", "{fields}", ], [ { fields => 3, index => 0 }, "{index}", "_mapping", "field", "{fields}", ], [ { fields => 3, type => 1 }, "_mapping", "{type}", "field", "{fields}", ], [ { fields => 2 }, "_mapping", "field", "{fields}" ], ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", include_defaults => "boolean", include_type_name => "boolean", local => "boolean", }, }, 'indices.get_index_template' => { doc => "indices-templates", parts => { name => { multi => 1 } }, paths => [ [ { name => 1 }, "_index_template", "{name}" ], [ {}, "_index_template" ], ], qs => { error_trace => "boolean", filter_path => "list", flat_settings => "boolean", human => "boolean", local => "boolean", master_timeout => "time", }, }, 'indices.get_mapping' => { doc => "indices-get-mapping", parts => { index => { multi => 1 }, type => { multi => 1 } }, paths => [ [ { index => 0, type => 2 }, "{index}", "_mapping", "{type}" ], [ { index => 0 }, "{index}", "_mapping" ], [ { type => 1 }, "_mapping", "{type}" ], [ {}, "_mapping" ], ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", include_type_name => "boolean", local => "boolean", master_timeout => "time", }, }, 'indices.get_settings' => { doc => "indices-get-settings", parts => { index => { multi => 1 }, name => { multi => 1 } }, paths => [ [ { index => 0, name => 2 }, "{index}", "_settings", "{name}" ], [ { index => 0 }, "{index}", "_settings" ], [ { name => 1 }, "_settings", "{name}" ], [ {}, "_settings" ], ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", flat_settings => "boolean", human => "boolean", ignore_unavailable => "boolean", include_defaults => "boolean", local => "boolean", master_timeout => "time", }, }, 'indices.get_template' => { doc => "indices-templates", parts => { name => { multi => 1 } }, paths => [ [ { name => 1 }, "_template", "{name}" ], [ {}, "_template" ] ], qs => { error_trace => "boolean", filter_path => "list", flat_settings => "boolean", human => "boolean", include_type_name => "boolean", local => "boolean", master_timeout => "time", }, }, 'indices.get_upgrade' => { doc => "indices-upgrade", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}", "_upgrade" ], [ {}, "_upgrade" ] ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", }, }, 'indices.migrate_to_data_stream' => { doc => "data-streams", method => "POST", parts => { name => {} }, paths => [ [ { name => 2 }, "_data_stream", "_migrate", "{name}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'indices.open' => { doc => "indices-open-close", method => "POST", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}", "_open" ] ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", master_timeout => "time", timeout => "time", wait_for_active_shards => "string", }, }, 'indices.promote_data_stream' => { doc => "data-streams", method => "POST", parts => { name => {} }, paths => [ [ { name => 2 }, "_data_stream", "_promote", "{name}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'indices.put_alias' => { body => {}, doc => "indices-aliases", method => "PUT", parts => { index => { multi => 1 }, name => {} }, paths => [ [ { index => 0, name => 2 }, "{index}", "_alias", "{name}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", timeout => "time", }, }, 'indices.put_index_template' => { body => { required => 1 }, doc => "indices-templates", method => "PUT", parts => { name => {} }, paths => [ [ { name => 1 }, "_index_template", "{name}" ] ], qs => { cause => "string", create => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", }, }, 'indices.put_mapping' => { body => { required => 1 }, doc => "indices-put-mapping", method => "PUT", parts => { index => { multi => 1 }, type => {} }, paths => [ [ { index => 0, type => 2 }, "{index}", "_mapping", "{type}" ], [ { index => 0 }, "{index}", "_mapping" ], [ { type => 1 }, "_mapping", "{type}" ], ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", include_type_name => "boolean", master_timeout => "time", timeout => "time", write_index_only => "boolean", }, }, 'indices.put_settings' => { body => { required => 1 }, doc => "indices-update-settings", method => "PUT", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}", "_settings" ], [ {}, "_settings" ] ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", flat_settings => "boolean", human => "boolean", ignore_unavailable => "boolean", master_timeout => "time", preserve_existing => "boolean", timeout => "time", }, }, 'indices.put_template' => { body => { required => 1 }, doc => "indices-templates", method => "PUT", parts => { name => {} }, paths => [ [ { name => 1 }, "_template", "{name}" ] ], qs => { create => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", include_type_name => "boolean", master_timeout => "time", order => "number", }, }, 'indices.recovery' => { doc => "indices-recovery", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}", "_recovery" ], [ {}, "_recovery" ] ], qs => { active_only => "boolean", detailed => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", }, }, 'indices.refresh' => { doc => "indices-refresh", method => "POST", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}", "_refresh" ], [ {}, "_refresh" ] ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", }, }, 'indices.reload_search_analyzers' => { doc => "indices-reload-analyzers", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}", "_reload_search_analyzers" ] ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", }, }, 'indices.resolve_index' => { doc => "indices-resolve-index-api", parts => { name => { multi => 1 } }, paths => [ [ { name => 2 }, "_resolve", "index", "{name}" ] ], qs => { error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", }, }, 'indices.rollover' => { body => {}, doc => "indices-rollover-index", method => "POST", parts => { alias => {}, new_index => {} }, paths => [ [ { alias => 0, new_index => 2 }, "{alias}", "_rollover", "{new_index}", ], [ { alias => 0 }, "{alias}", "_rollover" ], ], qs => { dry_run => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", include_type_name => "boolean", master_timeout => "time", timeout => "time", wait_for_active_shards => "string", }, }, 'indices.segments' => { doc => "indices-segments", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}", "_segments" ], [ {}, "_segments" ] ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", verbose => "boolean", }, }, 'indices.shard_stores' => { doc => "indices-shards-stores", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}", "_shard_stores" ], [ {}, "_shard_stores" ], ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", status => "list", }, }, 'indices.shrink' => { body => {}, doc => "indices-shrink-index", method => "PUT", parts => { index => {}, target => {} }, paths => [ [ { index => 0, target => 2 }, "{index}", "_shrink", "{target}" ], ], qs => { copy_settings => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", timeout => "time", wait_for_active_shards => "string", }, }, 'indices.simulate_index_template' => { body => {}, doc => "indices-templates", method => "POST", parts => { name => {} }, paths => [ [ { name => 2 }, "_index_template", "_simulate_index", "{name}" ], ], qs => { cause => "string", create => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", }, }, 'indices.simulate_template' => { body => {}, doc => "indices-templates", method => "POST", parts => { name => {} }, paths => [ [ { name => 2 }, "_index_template", "_simulate", "{name}" ], [ {}, "_index_template", "_simulate" ], ], qs => { cause => "string", create => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", }, }, 'indices.split' => { body => {}, doc => "indices-split-index", method => "PUT", parts => { index => {}, target => {} }, paths => [ [ { index => 0, target => 2 }, "{index}", "_split", "{target}" ], ], qs => { copy_settings => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", timeout => "time", wait_for_active_shards => "string", }, }, 'indices.stats' => { doc => "indices-stats", parts => { index => { multi => 1 }, metric => { multi => 1 } }, paths => [ [ { index => 0, metric => 2 }, "{index}", "_stats", "{metric}" ], [ { index => 0 }, "{index}", "_stats" ], [ { metric => 1 }, "_stats", "{metric}" ], [ {}, "_stats" ], ], qs => { completion_fields => "list", error_trace => "boolean", expand_wildcards => "enum", fielddata_fields => "list", fields => "list", filter_path => "list", forbid_closed_indices => "boolean", groups => "list", human => "boolean", include_segment_file_sizes => "boolean", include_unloaded_segments => "boolean", level => "enum", types => "list", }, }, 'indices.unfreeze' => { doc => "unfreeze-index-api", method => "POST", parts => { index => {} }, paths => [ [ { index => 0 }, "{index}", "_unfreeze" ] ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", master_timeout => "time", timeout => "time", wait_for_active_shards => "string", }, }, 'indices.update_aliases' => { body => { required => 1 }, doc => "indices-aliases", method => "POST", parts => {}, paths => [ [ {}, "_aliases" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", timeout => "time", }, }, 'indices.upgrade' => { doc => "indices-upgrade", method => "POST", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}", "_upgrade" ], [ {}, "_upgrade" ] ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", only_ancient_segments => "boolean", wait_for_completion => "boolean", }, }, 'indices.validate_query' => { body => {}, doc => "search-validate", parts => { index => { multi => 1 }, type => { multi => 1 } }, paths => [ [ { index => 0, type => 1 }, "{index}", "{type}", "_validate", "query", ], [ { index => 0 }, "{index}", "_validate", "query" ], [ {}, "_validate", "query" ], ], qs => { all_shards => "boolean", allow_no_indices => "boolean", analyze_wildcard => "boolean", analyzer => "string", default_operator => "enum", df => "string", error_trace => "boolean", expand_wildcards => "enum", explain => "boolean", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", lenient => "boolean", q => "string", rewrite => "boolean", }, }, 'ingest.delete_pipeline' => { doc => "delete-pipeline-api", method => "DELETE", parts => { id => {} }, paths => [ [ { id => 2 }, "_ingest", "pipeline", "{id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", timeout => "time", }, }, 'ingest.geo_ip_stats' => { doc => "geoip-stats-api", parts => {}, paths => [ [ {}, "_ingest", "geoip", "stats" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ingest.get_pipeline' => { doc => "get-pipeline-api", parts => { id => {} }, paths => [ [ { id => 2 }, "_ingest", "pipeline", "{id}" ], [ {}, "_ingest", "pipeline" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", summary => "boolean", }, }, 'ingest.processor_grok' => { doc => "", parts => {}, paths => [ [ {}, "_ingest", "processor", "grok" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ingest.put_pipeline' => { body => { required => 1 }, doc => "put-pipeline-api", method => "PUT", parts => { id => {} }, paths => [ [ { id => 2 }, "_ingest", "pipeline", "{id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", timeout => "time", }, }, 'ingest.simulate' => { body => { required => 1 }, doc => "simulate-pipeline-api", parts => { id => {} }, paths => [ [ { id => 2 }, "_ingest", "pipeline", "{id}", "_simulate" ], [ {}, "_ingest", "pipeline", "_simulate" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", verbose => "boolean", }, }, 'license.delete' => { doc => "delete-license", method => "DELETE", parts => {}, paths => [ [ {}, "_license" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'license.get' => { doc => "get-license", parts => {}, paths => [ [ {}, "_license" ] ], qs => { accept_enterprise => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", local => "boolean", }, }, 'license.get_basic_status' => { doc => "get-basic-status", parts => {}, paths => [ [ {}, "_license", "basic_status" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'license.get_trial_status' => { doc => "get-trial-status", parts => {}, paths => [ [ {}, "_license", "trial_status" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'license.post' => { body => {}, doc => "update-license", method => "PUT", parts => {}, paths => [ [ {}, "_license" ] ], qs => { acknowledge => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", }, }, 'license.post_start_basic' => { doc => "start-basic", method => "POST", parts => {}, paths => [ [ {}, "_license", "start_basic" ] ], qs => { acknowledge => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", }, }, 'license.post_start_trial' => { doc => "start-trial", method => "POST", parts => {}, paths => [ [ {}, "_license", "start_trial" ] ], qs => { acknowledge => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", type => "string", }, }, 'logstash.delete_pipeline' => { doc => "logstash-api-delete-pipeline", method => "DELETE", parts => { id => {} }, paths => [ [ { id => 2 }, "_logstash", "pipeline", "{id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'logstash.get_pipeline' => { doc => "logstash-api-get-pipeline", parts => { id => {} }, paths => [ [ { id => 2 }, "_logstash", "pipeline", "{id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'logstash.put_pipeline' => { body => { required => 1 }, doc => "logstash-api-put-pipeline", method => "PUT", parts => { id => {} }, paths => [ [ { id => 2 }, "_logstash", "pipeline", "{id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'migration.deprecations' => { doc => "migration-api-deprecation", parts => { index => {} }, paths => [ [ { index => 0 }, "{index}", "_migration", "deprecations" ], [ {}, "_migration", "deprecations" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.close_job' => { body => {}, doc => "ml-close-job", method => "POST", parts => { job_id => {} }, paths => [ [ { job_id => 2 }, "_ml", "anomaly_detectors", "{job_id}", "_close", ], ], qs => { allow_no_jobs => "boolean", allow_no_match => "boolean", error_trace => "boolean", filter_path => "list", force => "boolean", human => "boolean", timeout => "time", }, }, 'ml.delete_calendar' => { doc => "ml-delete-calendar", method => "DELETE", parts => { calendar_id => {} }, paths => [ [ { calendar_id => 2 }, "_ml", "calendars", "{calendar_id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.delete_calendar_event' => { doc => "ml-delete-calendar-event", method => "DELETE", parts => { calendar_id => {}, event_id => {} }, paths => [ [ { calendar_id => 2, event_id => 4 }, "_ml", "calendars", "{calendar_id}", "events", "{event_id}", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.delete_calendar_job' => { doc => "ml-delete-calendar-job", method => "DELETE", parts => { calendar_id => {}, job_id => {} }, paths => [ [ { calendar_id => 2, job_id => 4 }, "_ml", "calendars", "{calendar_id}", "jobs", "{job_id}", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.delete_data_frame_analytics' => { doc => "delete-dfanalytics", method => "DELETE", parts => { id => {} }, paths => [ [ { id => 3 }, "_ml", "data_frame", "analytics", "{id}" ] ], qs => { error_trace => "boolean", filter_path => "list", force => "boolean", human => "boolean", timeout => "time", }, }, 'ml.delete_datafeed' => { doc => "ml-delete-datafeed", method => "DELETE", parts => { datafeed_id => {} }, paths => [ [ { datafeed_id => 2 }, "_ml", "datafeeds", "{datafeed_id}" ] ], qs => { error_trace => "boolean", filter_path => "list", force => "boolean", human => "boolean", }, }, 'ml.delete_expired_data' => { body => {}, doc => "ml-delete-expired-data", method => "DELETE", parts => { job_id => {} }, paths => [ [ { job_id => 2 }, "_ml", "_delete_expired_data", "{job_id}" ], [ {}, "_ml", "_delete_expired_data" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", requests_per_second => "number", timeout => "time", }, }, 'ml.delete_filter' => { doc => "ml-delete-filter", method => "DELETE", parts => { filter_id => {} }, paths => [ [ { filter_id => 2 }, "_ml", "filters", "{filter_id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.delete_forecast' => { doc => "ml-delete-forecast", method => "DELETE", parts => { forecast_id => {}, job_id => {} }, paths => [ [ { forecast_id => 4, job_id => 2 }, "_ml", "anomaly_detectors", "{job_id}", "_forecast", "{forecast_id}", ], [ { job_id => 2 }, "_ml", "anomaly_detectors", "{job_id}", "_forecast", ], ], qs => { allow_no_forecasts => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", timeout => "time", }, }, 'ml.delete_job' => { doc => "ml-delete-job", method => "DELETE", parts => { job_id => {} }, paths => [ [ { job_id => 2 }, "_ml", "anomaly_detectors", "{job_id}" ] ], qs => { error_trace => "boolean", filter_path => "list", force => "boolean", human => "boolean", wait_for_completion => "boolean", }, }, 'ml.delete_model_snapshot' => { doc => "ml-delete-snapshot", method => "DELETE", parts => { job_id => {}, snapshot_id => {} }, paths => [ [ { job_id => 2, snapshot_id => 4 }, "_ml", "anomaly_detectors", "{job_id}", "model_snapshots", "{snapshot_id}", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.delete_trained_model' => { doc => "delete-trained-models", method => "DELETE", parts => { model_id => {} }, paths => [ [ { model_id => 2 }, "_ml", "trained_models", "{model_id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.delete_trained_model_alias' => { doc => "delete-trained-models-aliases", method => "DELETE", parts => { model_alias => {}, model_id => {} }, paths => [ [ { model_alias => 4, model_id => 2 }, "_ml", "trained_models", "{model_id}", "model_aliases", "{model_alias}", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.estimate_model_memory' => { body => { required => 1 }, doc => "ml-apis", method => "POST", parts => {}, paths => [ [ {}, "_ml", "anomaly_detectors", "_estimate_model_memory" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.evaluate_data_frame' => { body => { required => 1 }, doc => "evaluate-dfanalytics", method => "POST", parts => {}, paths => [ [ {}, "_ml", "data_frame", "_evaluate" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.explain_data_frame_analytics' => { body => {}, doc => "explain-dfanalytics", parts => { id => {} }, paths => [ [ { id => 3 }, "_ml", "data_frame", "analytics", "{id}", "_explain" ], [ {}, "_ml", "data_frame", "analytics", "_explain" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.find_file_structure' => { body => { required => 1 }, doc => "find-structure", method => "POST", parts => {}, paths => [ [ {}, "_ml", "find_file_structure" ] ], qs => { charset => "string", column_names => "list", delimiter => "string", error_trace => "boolean", explain => "boolean", filter_path => "list", format => "enum", grok_pattern => "string", has_header_row => "boolean", human => "boolean", line_merge_size_limit => "int", lines_to_sample => "int", quote => "string", should_trim_fields => "boolean", timeout => "time", timestamp_field => "string", timestamp_format => "string", }, serialize => "bulk", }, 'ml.flush_job' => { body => {}, doc => "ml-flush-job", method => "POST", parts => { job_id => {} }, paths => [ [ { job_id => 2 }, "_ml", "anomaly_detectors", "{job_id}", "_flush", ], ], qs => { advance_time => "string", calc_interim => "boolean", end => "string", error_trace => "boolean", filter_path => "list", human => "boolean", skip_time => "string", start => "string", }, }, 'ml.forecast' => { doc => "ml-forecast", method => "POST", parts => { job_id => {} }, paths => [ [ { job_id => 2 }, "_ml", "anomaly_detectors", "{job_id}", "_forecast", ], ], qs => { duration => "time", error_trace => "boolean", expires_in => "time", filter_path => "list", human => "boolean", max_model_memory => "string", }, }, 'ml.get_buckets' => { body => {}, doc => "ml-get-bucket", parts => { job_id => {}, timestamp => {} }, paths => [ [ { job_id => 2, timestamp => 5 }, "_ml", "anomaly_detectors", "{job_id}", "results", "buckets", "{timestamp}", ], [ { job_id => 2 }, "_ml", "anomaly_detectors", "{job_id}", "results", "buckets", ], ], qs => { anomaly_score => "double", desc => "boolean", end => "string", error_trace => "boolean", exclude_interim => "boolean", expand => "boolean", filter_path => "list", from => "int", human => "boolean", size => "int", sort => "string", start => "string", }, }, 'ml.get_calendar_events' => { doc => "ml-get-calendar-event", parts => { calendar_id => {} }, paths => [ [ { calendar_id => 2 }, "_ml", "calendars", "{calendar_id}", "events", ], ], qs => { end => "time", error_trace => "boolean", filter_path => "list", from => "int", human => "boolean", job_id => "string", size => "int", start => "string", }, }, 'ml.get_calendars' => { body => {}, doc => "ml-get-calendar", parts => { calendar_id => {} }, paths => [ [ { calendar_id => 2 }, "_ml", "calendars", "{calendar_id}" ], [ {}, "_ml", "calendars" ], ], qs => { error_trace => "boolean", filter_path => "list", from => "int", human => "boolean", size => "int", }, }, 'ml.get_categories' => { body => {}, doc => "ml-get-category", parts => { category_id => {}, job_id => {} }, paths => [ [ { category_id => 5, job_id => 2 }, "_ml", "anomaly_detectors", "{job_id}", "results", "categories", "{category_id}", ], [ { job_id => 2 }, "_ml", "anomaly_detectors", "{job_id}", "results", "categories", ], ], qs => { error_trace => "boolean", filter_path => "list", from => "int", human => "boolean", partition_field_value => "string", size => "int", }, }, 'ml.get_data_frame_analytics' => { doc => "get-dfanalytics", parts => { id => {} }, paths => [ [ { id => 3 }, "_ml", "data_frame", "analytics", "{id}" ], [ {}, "_ml", "data_frame", "analytics" ], ], qs => { allow_no_match => "boolean", error_trace => "boolean", exclude_generated => "boolean", filter_path => "list", from => "int", human => "boolean", size => "int", }, }, 'ml.get_data_frame_analytics_stats' => { doc => "get-dfanalytics-stats", parts => { id => {} }, paths => [ [ { id => 3 }, "_ml", "data_frame", "analytics", "{id}", "_stats" ], [ {}, "_ml", "data_frame", "analytics", "_stats" ], ], qs => { allow_no_match => "boolean", error_trace => "boolean", filter_path => "list", from => "int", human => "boolean", size => "int", verbose => "boolean", }, }, 'ml.get_datafeed_stats' => { doc => "ml-get-datafeed-stats", parts => { datafeed_id => {} }, paths => [ [ { datafeed_id => 2 }, "_ml", "datafeeds", "{datafeed_id}", "_stats", ], [ {}, "_ml", "datafeeds", "_stats" ], ], qs => { allow_no_datafeeds => "boolean", allow_no_match => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", }, }, 'ml.get_datafeeds' => { doc => "ml-get-datafeed", parts => { datafeed_id => {} }, paths => [ [ { datafeed_id => 2 }, "_ml", "datafeeds", "{datafeed_id}" ], [ {}, "_ml", "datafeeds" ], ], qs => { allow_no_datafeeds => "boolean", allow_no_match => "boolean", error_trace => "boolean", exclude_generated => "boolean", filter_path => "list", human => "boolean", }, }, 'ml.get_filters' => { doc => "ml-get-filter", parts => { filter_id => {} }, paths => [ [ { filter_id => 2 }, "_ml", "filters", "{filter_id}" ], [ {}, "_ml", "filters" ], ], qs => { error_trace => "boolean", filter_path => "list", from => "int", human => "boolean", size => "int", }, }, 'ml.get_influencers' => { body => {}, doc => "ml-get-influencer", parts => { job_id => {} }, paths => [ [ { job_id => 2 }, "_ml", "anomaly_detectors", "{job_id}", "results", "influencers", ], ], qs => { desc => "boolean", end => "string", error_trace => "boolean", exclude_interim => "boolean", filter_path => "list", from => "int", human => "boolean", influencer_score => "double", size => "int", sort => "string", start => "string", }, }, 'ml.get_job_stats' => { doc => "ml-get-job-stats", parts => { job_id => {} }, paths => [ [ { job_id => 2 }, "_ml", "anomaly_detectors", "{job_id}", "_stats", ], [ {}, "_ml", "anomaly_detectors", "_stats" ], ], qs => { allow_no_jobs => "boolean", allow_no_match => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", }, }, 'ml.get_jobs' => { doc => "ml-get-job", parts => { job_id => {} }, paths => [ [ { job_id => 2 }, "_ml", "anomaly_detectors", "{job_id}" ], [ {}, "_ml", "anomaly_detectors" ], ], qs => { allow_no_jobs => "boolean", allow_no_match => "boolean", error_trace => "boolean", exclude_generated => "boolean", filter_path => "list", human => "boolean", }, }, 'ml.get_model_snapshots' => { body => {}, doc => "ml-get-snapshot", parts => { job_id => {}, snapshot_id => {} }, paths => [ [ { job_id => 2, snapshot_id => 4 }, "_ml", "anomaly_detectors", "{job_id}", "model_snapshots", "{snapshot_id}", ], [ { job_id => 2 }, "_ml", "anomaly_detectors", "{job_id}", "model_snapshots", ], ], qs => { desc => "boolean", end => "time", error_trace => "boolean", filter_path => "list", from => "int", human => "boolean", size => "int", sort => "string", start => "time", }, }, 'ml.get_overall_buckets' => { body => {}, doc => "ml-get-overall-buckets", parts => { job_id => {} }, paths => [ [ { job_id => 2 }, "_ml", "anomaly_detectors", "{job_id}", "results", "overall_buckets", ], ], qs => { allow_no_jobs => "boolean", allow_no_match => "boolean", bucket_span => "string", end => "string", error_trace => "boolean", exclude_interim => "boolean", filter_path => "list", human => "boolean", overall_score => "double", start => "string", top_n => "int", }, }, 'ml.get_records' => { body => {}, doc => "ml-get-record", parts => { job_id => {} }, paths => [ [ { job_id => 2 }, "_ml", "anomaly_detectors", "{job_id}", "results", "records", ], ], qs => { desc => "boolean", end => "string", error_trace => "boolean", exclude_interim => "boolean", filter_path => "list", from => "int", human => "boolean", record_score => "double", size => "int", sort => "string", start => "string", }, }, 'ml.get_trained_models' => { doc => "get-trained-models", parts => { model_id => {} }, paths => [ [ { model_id => 2 }, "_ml", "trained_models", "{model_id}" ], [ {}, "_ml", "trained_models" ], ], qs => { allow_no_match => "boolean", decompress_definition => "boolean", error_trace => "boolean", exclude_generated => "boolean", filter_path => "list", from => "int", human => "boolean", include => "string", include_model_definition => "boolean", size => "int", tags => "list", }, }, 'ml.get_trained_models_stats' => { doc => "get-trained-models-stats", parts => { model_id => {} }, paths => [ [ { model_id => 2 }, "_ml", "trained_models", "{model_id}", "_stats", ], [ {}, "_ml", "trained_models", "_stats" ], ], qs => { allow_no_match => "boolean", error_trace => "boolean", filter_path => "list", from => "int", human => "boolean", size => "int", }, }, 'ml.info' => { doc => "get-ml-info", parts => {}, paths => [ [ {}, "_ml", "info" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.open_job' => { doc => "ml-open-job", method => "POST", parts => { job_id => {} }, paths => [ [ { job_id => 2 }, "_ml", "anomaly_detectors", "{job_id}", "_open" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.post_calendar_events' => { body => { required => 1 }, doc => "ml-post-calendar-event", method => "POST", parts => { calendar_id => {} }, paths => [ [ { calendar_id => 2 }, "_ml", "calendars", "{calendar_id}", "events", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.post_data' => { body => { required => 1 }, doc => "ml-post-data", method => "POST", parts => { job_id => {} }, paths => [ [ { job_id => 2 }, "_ml", "anomaly_detectors", "{job_id}", "_data" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", reset_end => "string", reset_start => "string", }, serialize => "bulk", }, 'ml.preview_data_frame_analytics' => { body => {}, doc => "preview-dfanalytics", parts => { id => {} }, paths => [ [ { id => 3 }, "_ml", "data_frame", "analytics", "{id}", "_preview" ], [ {}, "_ml", "data_frame", "analytics", "_preview" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.preview_datafeed' => { body => {}, doc => "ml-preview-datafeed", parts => { datafeed_id => {} }, paths => [ [ { datafeed_id => 2 }, "_ml", "datafeeds", "{datafeed_id}", "_preview", ], [ {}, "_ml", "datafeeds", "_preview" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.put_calendar' => { body => {}, doc => "ml-put-calendar", method => "PUT", parts => { calendar_id => {} }, paths => [ [ { calendar_id => 2 }, "_ml", "calendars", "{calendar_id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.put_calendar_job' => { doc => "ml-put-calendar-job", method => "PUT", parts => { calendar_id => {}, job_id => {} }, paths => [ [ { calendar_id => 2, job_id => 4 }, "_ml", "calendars", "{calendar_id}", "jobs", "{job_id}", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.put_data_frame_analytics' => { body => { required => 1 }, doc => "put-dfanalytics", method => "PUT", parts => { id => {} }, paths => [ [ { id => 3 }, "_ml", "data_frame", "analytics", "{id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.put_datafeed' => { body => { required => 1 }, doc => "ml-put-datafeed", method => "PUT", parts => { datafeed_id => {} }, paths => [ [ { datafeed_id => 2 }, "_ml", "datafeeds", "{datafeed_id}" ] ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_throttled => "boolean", ignore_unavailable => "boolean", }, }, 'ml.put_filter' => { body => { required => 1 }, doc => "ml-put-filter", method => "PUT", parts => { filter_id => {} }, paths => [ [ { filter_id => 2 }, "_ml", "filters", "{filter_id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.put_job' => { body => { required => 1 }, doc => "ml-put-job", method => "PUT", parts => { job_id => {} }, paths => [ [ { job_id => 2 }, "_ml", "anomaly_detectors", "{job_id}" ] ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_throttled => "boolean", ignore_unavailable => "boolean", }, }, 'ml.put_trained_model' => { body => { required => 1 }, doc => "put-trained-models", method => "PUT", parts => { model_id => {} }, paths => [ [ { model_id => 2 }, "_ml", "trained_models", "{model_id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.put_trained_model_alias' => { doc => "put-trained-models-aliases", method => "PUT", parts => { model_alias => {}, model_id => {} }, paths => [ [ { model_alias => 4, model_id => 2 }, "_ml", "trained_models", "{model_id}", "model_aliases", "{model_alias}", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", reassign => "boolean", }, }, 'ml.reset_job' => { doc => "ml-reset-job", method => "POST", parts => { job_id => {} }, paths => [ [ { job_id => 2 }, "_ml", "anomaly_detectors", "{job_id}", "_reset", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", wait_for_completion => "boolean", }, }, 'ml.revert_model_snapshot' => { body => {}, doc => "ml-revert-snapshot", method => "POST", parts => { job_id => {}, snapshot_id => {} }, paths => [ [ { job_id => 2, snapshot_id => 4 }, "_ml", "anomaly_detectors", "{job_id}", "model_snapshots", "{snapshot_id}", "_revert", ], ], qs => { delete_intervening_results => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", }, }, 'ml.set_upgrade_mode' => { doc => "ml-set-upgrade-mode", method => "POST", parts => {}, paths => [ [ {}, "_ml", "set_upgrade_mode" ] ], qs => { enabled => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", timeout => "time", }, }, 'ml.start_data_frame_analytics' => { body => {}, doc => "start-dfanalytics", method => "POST", parts => { id => {} }, paths => [ [ { id => 3 }, "_ml", "data_frame", "analytics", "{id}", "_start" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", timeout => "time", }, }, 'ml.start_datafeed' => { body => {}, doc => "ml-start-datafeed", method => "POST", parts => { datafeed_id => {} }, paths => [ [ { datafeed_id => 2 }, "_ml", "datafeeds", "{datafeed_id}", "_start", ], ], qs => { end => "string", error_trace => "boolean", filter_path => "list", human => "boolean", start => "string", timeout => "time", }, }, 'ml.stop_data_frame_analytics' => { body => {}, doc => "stop-dfanalytics", method => "POST", parts => { id => {} }, paths => [ [ { id => 3 }, "_ml", "data_frame", "analytics", "{id}", "_stop" ], ], qs => { allow_no_match => "boolean", error_trace => "boolean", filter_path => "list", force => "boolean", human => "boolean", timeout => "time", }, }, 'ml.stop_datafeed' => { body => {}, doc => "ml-stop-datafeed", method => "POST", parts => { datafeed_id => {} }, paths => [ [ { datafeed_id => 2 }, "_ml", "datafeeds", "{datafeed_id}", "_stop", ], ], qs => { allow_no_datafeeds => "boolean", allow_no_match => "boolean", error_trace => "boolean", filter_path => "list", force => "boolean", human => "boolean", timeout => "time", }, }, 'ml.update_data_frame_analytics' => { body => { required => 1 }, doc => "update-dfanalytics", method => "POST", parts => { id => {} }, paths => [ [ { id => 3 }, "_ml", "data_frame", "analytics", "{id}", "_update" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.update_datafeed' => { body => { required => 1 }, doc => "ml-update-datafeed", method => "POST", parts => { datafeed_id => {} }, paths => [ [ { datafeed_id => 2 }, "_ml", "datafeeds", "{datafeed_id}", "_update", ], ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_throttled => "boolean", ignore_unavailable => "boolean", }, }, 'ml.update_filter' => { body => { required => 1 }, doc => "ml-update-filter", method => "POST", parts => { filter_id => {} }, paths => [ [ { filter_id => 2 }, "_ml", "filters", "{filter_id}", "_update" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.update_job' => { body => { required => 1 }, doc => "ml-update-job", method => "POST", parts => { job_id => {} }, paths => [ [ { job_id => 2 }, "_ml", "anomaly_detectors", "{job_id}", "_update", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.update_model_snapshot' => { body => { required => 1 }, doc => "ml-update-snapshot", method => "POST", parts => { job_id => {}, snapshot_id => {} }, paths => [ [ { job_id => 2, snapshot_id => 4 }, "_ml", "anomaly_detectors", "{job_id}", "model_snapshots", "{snapshot_id}", "_update", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.upgrade_job_snapshot' => { doc => "ml-upgrade-job-model-snapshot", method => "POST", parts => { job_id => {}, snapshot_id => {} }, paths => [ [ { job_id => 2, snapshot_id => 4 }, "_ml", "anomaly_detectors", "{job_id}", "model_snapshots", "{snapshot_id}", "_upgrade", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", timeout => "time", wait_for_completion => "boolean", }, }, 'ml.validate' => { body => { required => 1 }, doc => "ml-jobs", method => "POST", parts => {}, paths => [ [ {}, "_ml", "anomaly_detectors", "_validate" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ml.validate_detector' => { body => { required => 1 }, doc => "ml-jobs", method => "POST", parts => {}, paths => [ [ {}, "_ml", "anomaly_detectors", "_validate", "detector" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'monitoring.bulk' => { body => { required => 1 }, doc => "monitor-elasticsearch-cluster", method => "POST", parts => { type => {} }, paths => [ [ { type => 1 }, "_monitoring", "{type}", "bulk" ], [ {}, "_monitoring", "bulk" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", interval => "string", system_api_version => "string", system_id => "string", }, serialize => "bulk", }, 'nodes.clear_repositories_metering_archive' => { doc => "clear-repositories-metering-archive-api", method => "DELETE", parts => { max_archive_version => {}, node_id => { multi => 1 } }, paths => [ [ { max_archive_version => 3, node_id => 1 }, "_nodes", "{node_id}", "_repositories_metering", "{max_archive_version}", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'nodes.get_repositories_metering_info' => { doc => "get-repositories-metering-api", parts => { node_id => { multi => 1 } }, paths => [ [ { node_id => 1 }, "_nodes", "{node_id}", "_repositories_metering", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'nodes.hot_threads' => { doc => "cluster-nodes-hot-threads", parts => { node_id => { multi => 1 } }, paths => [ [ { node_id => 1 }, "_nodes", "{node_id}", "hot_threads" ], [ {}, "_nodes", "hot_threads" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", ignore_idle_threads => "boolean", interval => "time", snapshots => "number", threads => "number", timeout => "time", type => "enum", }, }, 'nodes.info' => { doc => "cluster-nodes-info", parts => { metric => { multi => 1 }, node_id => { multi => 1 } }, paths => [ [ { metric => 2, node_id => 1 }, "_nodes", "{node_id}", "{metric}", ], [ { metric => 1 }, "_nodes", "{metric}" ], [ { node_id => 1 }, "_nodes", "{node_id}" ], [ {}, "_nodes" ], ], qs => { error_trace => "boolean", filter_path => "list", flat_settings => "boolean", human => "boolean", timeout => "time", }, }, 'nodes.reload_secure_settings' => { body => {}, doc => "", method => "POST", parts => { node_id => { multi => 1 } }, paths => [ [ { node_id => 1 }, "_nodes", "{node_id}", "reload_secure_settings", ], [ {}, "_nodes", "reload_secure_settings" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", timeout => "time", }, }, 'nodes.stats' => { doc => "cluster-nodes-stats", parts => { index_metric => { multi => 1 }, metric => { multi => 1 }, node_id => { multi => 1 }, }, paths => [ [ { index_metric => 4, metric => 3, node_id => 1 }, "_nodes", "{node_id}", "stats", "{metric}", "{index_metric}", ], [ { index_metric => 3, metric => 2 }, "_nodes", "stats", "{metric}", "{index_metric}", ], [ { metric => 3, node_id => 1 }, "_nodes", "{node_id}", "stats", "{metric}", ], [ { metric => 2 }, "_nodes", "stats", "{metric}" ], [ { node_id => 1 }, "_nodes", "{node_id}", "stats" ], [ {}, "_nodes", "stats" ], ], qs => { completion_fields => "list", error_trace => "boolean", fielddata_fields => "list", fields => "list", filter_path => "list", groups => "boolean", human => "boolean", include_segment_file_sizes => "boolean", include_unloaded_segments => "boolean", level => "enum", timeout => "time", types => "list", }, }, 'nodes.usage' => { doc => "cluster-nodes-usage", parts => { metric => { multi => 1 }, node_id => { multi => 1 } }, paths => [ [ { metric => 3, node_id => 1 }, "_nodes", "{node_id}", "usage", "{metric}", ], [ { metric => 2 }, "_nodes", "usage", "{metric}" ], [ { node_id => 1 }, "_nodes", "{node_id}", "usage" ], [ {}, "_nodes", "usage" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", timeout => "time", }, }, 'rollup.delete_job' => { doc => "rollup-delete-job", method => "DELETE", parts => { id => {} }, paths => [ [ { id => 2 }, "_rollup", "job", "{id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'rollup.get_jobs' => { doc => "rollup-get-job", parts => { id => {} }, paths => [ [ { id => 2 }, "_rollup", "job", "{id}" ], [ {}, "_rollup", "job" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'rollup.get_rollup_caps' => { doc => "rollup-get-rollup-caps", parts => { id => {} }, paths => [ [ { id => 2 }, "_rollup", "data", "{id}" ], [ {}, "_rollup", "data" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'rollup.get_rollup_index_caps' => { doc => "rollup-get-rollup-index-caps", parts => { index => {} }, paths => [ [ { index => 0 }, "{index}", "_rollup", "data" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'rollup.put_job' => { body => { required => 1 }, doc => "rollup-put-job", method => "PUT", parts => { id => {} }, paths => [ [ { id => 2 }, "_rollup", "job", "{id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'rollup.rollup' => { body => { required => 1 }, doc => "xpack-rollup", method => "POST", parts => { index => { required => 1 }, rollup_index => { required => 1 } }, paths => [ [ { index => 0, rollup_index => 2 }, "{index}", "_rollup", "{rollup_index}", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'rollup.rollup_search' => { body => { required => 1 }, doc => "rollup-search", parts => { index => { multi => 1 }, type => {} }, paths => [ [ { index => 0, type => 1 }, "{index}", "{type}", "_rollup_search", ], [ { index => 0 }, "{index}", "_rollup_search" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", rest_total_hits_as_int => "boolean", typed_keys => "boolean", }, }, 'rollup.start_job' => { doc => "rollup-start-job", method => "POST", parts => { id => {} }, paths => [ [ { id => 2 }, "_rollup", "job", "{id}", "_start" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'rollup.stop_job' => { doc => "rollup-stop-job", method => "POST", parts => { id => {} }, paths => [ [ { id => 2 }, "_rollup", "job", "{id}", "_stop" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", timeout => "time", wait_for_completion => "boolean", }, }, 'searchable_snapshots.cache_stats' => { doc => "searchable-snapshots-apis", parts => { node_id => { multi => 1 } }, paths => [ [ { node_id => 1 }, "_searchable_snapshots", "{node_id}", "cache", "stats", ], [ {}, "_searchable_snapshots", "cache", "stats" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'searchable_snapshots.clear_cache' => { doc => "searchable-snapshots-apis", method => "POST", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}", "_searchable_snapshots", "cache", "clear", ], [ {}, "_searchable_snapshots", "cache", "clear" ], ], qs => { allow_no_indices => "boolean", error_trace => "boolean", expand_wildcards => "enum", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", }, }, 'searchable_snapshots.mount' => { body => { required => 1 }, doc => "searchable-snapshots-api-mount-snapshot", method => "POST", parts => { repository => {}, snapshot => {} }, paths => [ [ { repository => 1, snapshot => 2 }, "_snapshot", "{repository}", "{snapshot}", "_mount", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", storage => "string", wait_for_completion => "boolean", }, }, 'searchable_snapshots.repository_stats' => { doc => "searchable-snapshots-apis", parts => { repository => {} }, paths => [ [ { repository => 1 }, "_snapshot", "{repository}", "_stats" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'searchable_snapshots.stats' => { doc => "searchable-snapshots-apis", parts => { index => { multi => 1 } }, paths => [ [ { index => 0 }, "{index}", "_searchable_snapshots", "stats" ], [ {}, "_searchable_snapshots", "stats" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", level => "enum", }, }, 'security.authenticate' => { doc => "security-api-authenticate", parts => {}, paths => [ [ {}, "_security", "_authenticate" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'security.change_password' => { body => { required => 1 }, doc => "security-api-change-password", method => "PUT", parts => { username => {} }, paths => [ [ { username => 2 }, "_security", "user", "{username}", "_password", ], [ {}, "_security", "user", "_password" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", refresh => "enum", }, }, 'security.clear_api_key_cache' => { doc => "security-api-clear-api-key-cache", method => "POST", parts => { ids => { multi => 1 } }, paths => [ [ { ids => 2 }, "_security", "api_key", "{ids}", "_clear_cache" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'security.clear_cached_privileges' => { doc => "security-api-clear-privilege-cache", method => "POST", parts => { application => { multi => 1 } }, paths => [ [ { application => 2 }, "_security", "privilege", "{application}", "_clear_cache", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'security.clear_cached_realms' => { doc => "security-api-clear-cache", method => "POST", parts => { realms => { multi => 1 } }, paths => [ [ { realms => 2 }, "_security", "realm", "{realms}", "_clear_cache", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", usernames => "list", }, }, 'security.clear_cached_roles' => { doc => "security-api-clear-role-cache", method => "POST", parts => { name => { multi => 1 } }, paths => [ [ { name => 2 }, "_security", "role", "{name}", "_clear_cache" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'security.clear_cached_service_tokens' => { doc => "security-api-clear-service-token-caches", method => "POST", parts => { name => { multi => 1 }, namespace => {}, service => {} }, paths => [ [ { name => 6, namespace => 2, service => 3 }, "_security", "service", "{namespace}", "{service}", "credential", "token", "{name}", "_clear_cache", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'security.create_api_key' => { body => { required => 1 }, doc => "security-api-create-api-key", method => "PUT", parts => {}, paths => [ [ {}, "_security", "api_key" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", refresh => "enum", }, }, 'security.create_service_token' => { doc => "security-api-create-service-token", method => "POST", parts => { name => {}, namespace => {}, service => {} }, paths => [ [ { name => 6, namespace => 2, service => 3 }, "_security", "service", "{namespace}", "{service}", "credential", "token", "{name}", ], [ { namespace => 2, service => 3 }, "_security", "service", "{namespace}", "{service}", "credential", "token", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", refresh => "enum", }, }, 'security.delete_privileges' => { doc => "security-api-delete-privilege", method => "DELETE", parts => { application => {}, name => {} }, paths => [ [ { application => 2, name => 3 }, "_security", "privilege", "{application}", "{name}", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", refresh => "enum", }, }, 'security.delete_role' => { doc => "security-api-delete-role", method => "DELETE", parts => { name => {} }, paths => [ [ { name => 2 }, "_security", "role", "{name}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", refresh => "enum", }, }, 'security.delete_role_mapping' => { doc => "security-api-delete-role-mapping", method => "DELETE", parts => { name => {} }, paths => [ [ { name => 2 }, "_security", "role_mapping", "{name}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", refresh => "enum", }, }, 'security.delete_service_token' => { doc => "security-api-delete-service-token", method => "DELETE", parts => { name => {}, namespace => {}, service => {} }, paths => [ [ { name => 6, namespace => 2, service => 3 }, "_security", "service", "{namespace}", "{service}", "credential", "token", "{name}", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", refresh => "enum", }, }, 'security.delete_user' => { doc => "security-api-delete-user", method => "DELETE", parts => { username => {} }, paths => [ [ { username => 2 }, "_security", "user", "{username}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", refresh => "enum", }, }, 'security.disable_user' => { doc => "security-api-disable-user", method => "PUT", parts => { username => {} }, paths => [ [ { username => 2 }, "_security", "user", "{username}", "_disable" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", refresh => "enum", }, }, 'security.enable_user' => { doc => "security-api-enable-user", method => "PUT", parts => { username => {} }, paths => [ [ { username => 2 }, "_security", "user", "{username}", "_enable" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", refresh => "enum", }, }, 'security.get_api_key' => { doc => "security-api-get-api-key", parts => {}, paths => [ [ {}, "_security", "api_key" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", id => "string", name => "string", owner => "boolean", realm_name => "string", username => "string", }, }, 'security.get_builtin_privileges' => { doc => "security-api-get-builtin-privileges", parts => {}, paths => [ [ {}, "_security", "privilege", "_builtin" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'security.get_privileges' => { doc => "security-api-get-privileges", parts => { application => {}, name => {} }, paths => [ [ { application => 2, name => 3 }, "_security", "privilege", "{application}", "{name}", ], [ { application => 2 }, "_security", "privilege", "{application}" ], [ {}, "_security", "privilege" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'security.get_role' => { doc => "security-api-get-role", parts => { name => { multi => 1 } }, paths => [ [ { name => 2 }, "_security", "role", "{name}" ], [ {}, "_security", "role" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'security.get_role_mapping' => { doc => "security-api-get-role-mapping", parts => { name => { multi => 1 } }, paths => [ [ { name => 2 }, "_security", "role_mapping", "{name}" ], [ {}, "_security", "role_mapping" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'security.get_service_accounts' => { doc => "security-api-get-service-accounts", parts => { namespace => {}, service => {} }, paths => [ [ { namespace => 2, service => 3 }, "_security", "service", "{namespace}", "{service}", ], [ { namespace => 2 }, "_security", "service", "{namespace}" ], [ {}, "_security", "service" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'security.get_service_credentials' => { doc => "security-api-get-service-credentials", parts => { namespace => {}, service => {} }, paths => [ [ { namespace => 2, service => 3 }, "_security", "service", "{namespace}", "{service}", "credential", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'security.get_token' => { body => { required => 1 }, doc => "security-api-get-token", method => "POST", parts => {}, paths => [ [ {}, "_security", "oauth2", "token" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'security.get_user' => { doc => "security-api-get-user", parts => { username => { multi => 1 } }, paths => [ [ { username => 2 }, "_security", "user", "{username}" ], [ {}, "_security", "user" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'security.get_user_privileges' => { doc => "security-api-get-user-privileges", parts => {}, paths => [ [ {}, "_security", "user", "_privileges" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'security.grant_api_key' => { body => { required => 1 }, doc => "security-api-grant-api-key", method => "POST", parts => {}, paths => [ [ {}, "_security", "api_key", "grant" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", refresh => "enum", }, }, 'security.has_privileges' => { body => { required => 1 }, doc => "security-api-has-privileges", parts => { user => {} }, paths => [ [ { user => 2 }, "_security", "user", "{user}", "_has_privileges" ], [ {}, "_security", "user", "_has_privileges" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'security.invalidate_api_key' => { body => { required => 1 }, doc => "security-api-invalidate-api-key", method => "DELETE", parts => {}, paths => [ [ {}, "_security", "api_key" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'security.invalidate_token' => { body => { required => 1 }, doc => "security-api-invalidate-token", method => "DELETE", parts => {}, paths => [ [ {}, "_security", "oauth2", "token" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'security.put_privileges' => { body => { required => 1 }, doc => "security-api-put-privileges", method => "PUT", parts => {}, paths => [ [ {}, "_security", "privilege" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", refresh => "enum", }, }, 'security.put_role' => { body => { required => 1 }, doc => "security-api-put-role", method => "PUT", parts => { name => {} }, paths => [ [ { name => 2 }, "_security", "role", "{name}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", refresh => "enum", }, }, 'security.put_role_mapping' => { body => { required => 1 }, doc => "security-api-put-role-mapping", method => "PUT", parts => { name => {} }, paths => [ [ { name => 2 }, "_security", "role_mapping", "{name}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", refresh => "enum", }, }, 'security.put_user' => { body => { required => 1 }, doc => "security-api-put-user", method => "PUT", parts => { username => {} }, paths => [ [ { username => 2 }, "_security", "user", "{username}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", refresh => "enum", }, }, 'security.query_api_keys' => { body => {}, doc => "security-api-query-api-key", parts => {}, paths => [ [ {}, "_security", "_query", "api_key" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'security.saml_authenticate' => { body => { required => 1 }, doc => "security-api-saml-authenticate", method => "POST", parts => {}, paths => [ [ {}, "_security", "saml", "authenticate" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'security.saml_complete_logout' => { body => { required => 1 }, doc => "security-api-saml-complete-logout", method => "POST", parts => {}, paths => [ [ {}, "_security", "saml", "complete_logout" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'security.saml_invalidate' => { body => { required => 1 }, doc => "security-api-saml-invalidate", method => "POST", parts => {}, paths => [ [ {}, "_security", "saml", "invalidate" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'security.saml_logout' => { body => { required => 1 }, doc => "security-api-saml-logout", method => "POST", parts => {}, paths => [ [ {}, "_security", "saml", "logout" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'security.saml_prepare_authentication' => { body => { required => 1 }, doc => "security-api-saml-prepare-authentication", method => "POST", parts => {}, paths => [ [ {}, "_security", "saml", "prepare" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'security.saml_service_provider_metadata' => { doc => "security-api-saml-sp-metadata", parts => { realm_name => {} }, paths => [ [ { realm_name => 3 }, "_security", "saml", "metadata", "{realm_name}", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'shutdown.delete_node' => { doc => "", method => "DELETE", parts => { node_id => {} }, paths => [ [ { node_id => 1 }, "_nodes", "{node_id}", "shutdown" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'shutdown.get_node' => { doc => "", parts => { node_id => {} }, paths => [ [ { node_id => 1 }, "_nodes", "{node_id}", "shutdown" ], [ {}, "_nodes", "shutdown" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'shutdown.put_node' => { body => { required => 1 }, doc => "", method => "PUT", parts => { node_id => {} }, paths => [ [ { node_id => 1 }, "_nodes", "{node_id}", "shutdown" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'slm.delete_lifecycle' => { doc => "slm-api-delete-policy", method => "DELETE", parts => { policy_id => {} }, paths => [ [ { policy_id => 2 }, "_slm", "policy", "{policy_id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'slm.execute_lifecycle' => { doc => "slm-api-execute-lifecycle", method => "PUT", parts => { policy_id => {} }, paths => [ [ { policy_id => 2 }, "_slm", "policy", "{policy_id}", "_execute" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'slm.execute_retention' => { doc => "slm-api-execute-retention", method => "POST", parts => {}, paths => [ [ {}, "_slm", "_execute_retention" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'slm.get_lifecycle' => { doc => "slm-api-get-policy", parts => { policy_id => { multi => 1 } }, paths => [ [ { policy_id => 2 }, "_slm", "policy", "{policy_id}" ], [ {}, "_slm", "policy" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'slm.get_stats' => { doc => "slm-api-get-stats", parts => {}, paths => [ [ {}, "_slm", "stats" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'slm.get_status' => { doc => "slm-api-get-status", parts => {}, paths => [ [ {}, "_slm", "status" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'slm.put_lifecycle' => { body => {}, doc => "slm-api-put-policy", method => "PUT", parts => { policy_id => {} }, paths => [ [ { policy_id => 2 }, "_slm", "policy", "{policy_id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'slm.start' => { doc => "slm-api-start", method => "POST", parts => {}, paths => [ [ {}, "_slm", "start" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'slm.stop' => { doc => "slm-api-stop", method => "POST", parts => {}, paths => [ [ {}, "_slm", "stop" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'snapshot.cleanup_repository' => { doc => "clean-up-snapshot-repo-api", method => "POST", parts => { repository => {} }, paths => [ [ { repository => 1 }, "_snapshot", "{repository}", "_cleanup" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", timeout => "time", }, }, 'snapshot.clone' => { body => { required => 1 }, doc => "modules-snapshots", method => "PUT", parts => { repository => {}, snapshot => {}, target_snapshot => {} }, paths => [ [ { repository => 1, snapshot => 2, target_snapshot => 4 }, "_snapshot", "{repository}", "{snapshot}", "_clone", "{target_snapshot}", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", }, }, 'snapshot.create' => { body => {}, doc => "modules-snapshots", method => "PUT", parts => { repository => {}, snapshot => {} }, paths => [ [ { repository => 1, snapshot => 2 }, "_snapshot", "{repository}", "{snapshot}", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", wait_for_completion => "boolean", }, }, 'snapshot.create_repository' => { body => { required => 1 }, doc => "modules-snapshots", method => "PUT", parts => { repository => {} }, paths => [ [ { repository => 1 }, "_snapshot", "{repository}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", timeout => "time", verify => "boolean", }, }, 'snapshot.delete' => { doc => "modules-snapshots", method => "DELETE", parts => { repository => {}, snapshot => {} }, paths => [ [ { repository => 1, snapshot => 2 }, "_snapshot", "{repository}", "{snapshot}", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", }, }, 'snapshot.delete_repository' => { doc => "modules-snapshots", method => "DELETE", parts => { repository => { multi => 1 } }, paths => [ [ { repository => 1 }, "_snapshot", "{repository}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", timeout => "time", }, }, 'snapshot.get' => { doc => "modules-snapshots", parts => { repository => {}, snapshot => { multi => 1 } }, paths => [ [ { repository => 1, snapshot => 2 }, "_snapshot", "{repository}", "{snapshot}", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", include_repository => "boolean", index_details => "boolean", master_timeout => "time", verbose => "boolean", }, }, 'snapshot.get_repository' => { doc => "modules-snapshots", parts => { repository => { multi => 1 } }, paths => [ [ { repository => 1 }, "_snapshot", "{repository}" ], [ {}, "_snapshot" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", local => "boolean", master_timeout => "time", }, }, 'snapshot.repository_analyze' => { doc => "modules-snapshots", method => "POST", parts => { repository => {} }, paths => [ [ { repository => 1 }, "_snapshot", "{repository}", "_analyze" ], ], qs => { blob_count => "number", concurrency => "number", detailed => "boolean", early_read_node_count => "number", error_trace => "boolean", filter_path => "list", human => "boolean", max_blob_size => "string", max_total_data_size => "string", rare_action_probability => "number", rarely_abort_writes => "boolean", read_node_count => "number", seed => "number", timeout => "time", }, }, 'snapshot.restore' => { body => {}, doc => "modules-snapshots", method => "POST", parts => { repository => {}, snapshot => {} }, paths => [ [ { repository => 1, snapshot => 2 }, "_snapshot", "{repository}", "{snapshot}", "_restore", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", wait_for_completion => "boolean", }, }, 'snapshot.status' => { doc => "modules-snapshots", parts => { repository => {}, snapshot => { multi => 1 } }, paths => [ [ { repository => 1, snapshot => 2 }, "_snapshot", "{repository}", "{snapshot}", "_status", ], [ { repository => 1 }, "_snapshot", "{repository}", "_status" ], [ {}, "_snapshot", "_status" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", ignore_unavailable => "boolean", master_timeout => "time", }, }, 'snapshot.verify_repository' => { doc => "modules-snapshots", method => "POST", parts => { repository => {} }, paths => [ [ { repository => 1 }, "_snapshot", "{repository}", "_verify" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", timeout => "time", }, }, 'sql.clear_cursor' => { body => { required => 1 }, doc => "clear-sql-cursor-api", method => "POST", parts => {}, paths => [ [ {}, "_sql", "close" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'sql.delete_async' => { doc => "delete-async-sql-search-api", method => "DELETE", parts => { id => {} }, paths => [ [ { id => 3 }, "_sql", "async", "delete", "{id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'sql.get_async' => { doc => "get-async-sql-search-api", parts => { id => {} }, paths => [ [ { id => 2 }, "_sql", "async", "{id}" ] ], qs => { delimiter => "string", error_trace => "boolean", filter_path => "list", format => "string", human => "boolean", keep_alive => "time", wait_for_completion_timeout => "time", }, }, 'sql.get_async_status' => { doc => "get-async-sql-search-status-api", parts => { id => {} }, paths => [ [ { id => 3 }, "_sql", "async", "status", "{id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'sql.query' => { body => { required => 1 }, doc => "sql-search-api", method => "POST", parts => {}, paths => [ [ {}, "_sql" ] ], qs => { error_trace => "boolean", filter_path => "list", format => "string", human => "boolean", }, }, 'sql.translate' => { body => { required => 1 }, doc => "sql-translate-api", method => "POST", parts => {}, paths => [ [ {}, "_sql", "translate" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'ssl.certificates' => { doc => "security-api-ssl", parts => {}, paths => [ [ {}, "_ssl", "certificates" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'tasks.cancel' => { doc => "tasks", method => "POST", parts => { task_id => {} }, paths => [ [ { task_id => 1 }, "_tasks", "{task_id}", "_cancel" ], [ {}, "_tasks", "_cancel" ], ], qs => { actions => "list", error_trace => "boolean", filter_path => "list", human => "boolean", nodes => "list", parent_task_id => "string", wait_for_completion => "boolean", }, }, 'tasks.get' => { doc => "tasks", parts => { task_id => {} }, paths => [ [ { task_id => 1 }, "_tasks", "{task_id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", timeout => "time", wait_for_completion => "boolean", }, }, 'tasks.list' => { doc => "tasks", parts => {}, paths => [ [ {}, "_tasks" ] ], qs => { actions => "list", detailed => "boolean", error_trace => "boolean", filter_path => "list", group_by => "enum", human => "boolean", nodes => "list", parent_task_id => "string", timeout => "time", wait_for_completion => "boolean", }, }, 'text_structure.find_structure' => { body => { required => 1 }, doc => "find-structure", method => "POST", parts => {}, paths => [ [ {}, "_text_structure", "find_structure" ] ], qs => { charset => "string", column_names => "list", delimiter => "string", error_trace => "boolean", explain => "boolean", filter_path => "list", format => "enum", grok_pattern => "string", has_header_row => "boolean", human => "boolean", line_merge_size_limit => "int", lines_to_sample => "int", quote => "string", should_trim_fields => "boolean", timeout => "time", timestamp_field => "string", timestamp_format => "string", }, serialize => "bulk", }, 'transform.delete_transform' => { doc => "delete-transform", method => "DELETE", parts => { transform_id => {} }, paths => [ [ { transform_id => 1 }, "_transform", "{transform_id}" ] ], qs => { error_trace => "boolean", filter_path => "list", force => "boolean", human => "boolean", }, }, 'transform.get_transform' => { doc => "get-transform", parts => { transform_id => {} }, paths => [ [ { transform_id => 1 }, "_transform", "{transform_id}" ], [ {}, "_transform" ], ], qs => { allow_no_match => "boolean", error_trace => "boolean", exclude_generated => "boolean", filter_path => "list", from => "int", human => "boolean", size => "int", }, }, 'transform.get_transform_stats' => { doc => "get-transform-stats", parts => { transform_id => {} }, paths => [ [ { transform_id => 1 }, "_transform", "{transform_id}", "_stats" ], ], qs => { allow_no_match => "boolean", error_trace => "boolean", filter_path => "list", from => "number", human => "boolean", size => "number", }, }, 'transform.preview_transform' => { body => { required => 1 }, doc => "preview-transform", method => "POST", parts => {}, paths => [ [ {}, "_transform", "_preview" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'transform.put_transform' => { body => { required => 1 }, doc => "put-transform", method => "PUT", parts => { transform_id => {} }, paths => [ [ { transform_id => 1 }, "_transform", "{transform_id}" ] ], qs => { defer_validation => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", }, }, 'transform.start_transform' => { doc => "start-transform", method => "POST", parts => { transform_id => {} }, paths => [ [ { transform_id => 1 }, "_transform", "{transform_id}", "_start" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", timeout => "time", }, }, 'transform.stop_transform' => { doc => "stop-transform", method => "POST", parts => { transform_id => {} }, paths => [ [ { transform_id => 1 }, "_transform", "{transform_id}", "_stop" ], ], qs => { allow_no_match => "boolean", error_trace => "boolean", filter_path => "list", force => "boolean", human => "boolean", timeout => "time", wait_for_checkpoint => "boolean", wait_for_completion => "boolean", }, }, 'transform.update_transform' => { body => { required => 1 }, doc => "update-transform", method => "POST", parts => { transform_id => { required => 1 } }, paths => [ [ { transform_id => 1 }, "_transform", "{transform_id}", "_update", ], ], qs => { defer_validation => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", }, }, 'watcher.ack_watch' => { doc => "watcher-api-ack-watch", method => "PUT", parts => { action_id => { multi => 1 }, watch_id => {} }, paths => [ [ { action_id => 4, watch_id => 2 }, "_watcher", "watch", "{watch_id}", "_ack", "{action_id}", ], [ { watch_id => 2 }, "_watcher", "watch", "{watch_id}", "_ack" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'watcher.activate_watch' => { doc => "watcher-api-activate-watch", method => "PUT", parts => { watch_id => {} }, paths => [ [ { watch_id => 2 }, "_watcher", "watch", "{watch_id}", "_activate", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'watcher.deactivate_watch' => { doc => "watcher-api-deactivate-watch", method => "PUT", parts => { watch_id => {} }, paths => [ [ { watch_id => 2 }, "_watcher", "watch", "{watch_id}", "_deactivate", ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'watcher.delete_watch' => { doc => "watcher-api-delete-watch", method => "DELETE", parts => { id => {} }, paths => [ [ { id => 2 }, "_watcher", "watch", "{id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'watcher.execute_watch' => { body => {}, doc => "watcher-api-execute-watch", method => "PUT", parts => { id => {} }, paths => [ [ { id => 2 }, "_watcher", "watch", "{id}", "_execute" ], [ {}, "_watcher", "watch", "_execute" ], ], qs => { debug => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", }, }, 'watcher.get_watch' => { doc => "watcher-api-get-watch", parts => { id => {} }, paths => [ [ { id => 2 }, "_watcher", "watch", "{id}" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'watcher.put_watch' => { body => {}, doc => "watcher-api-put-watch", method => "PUT", parts => { id => {} }, paths => [ [ { id => 2 }, "_watcher", "watch", "{id}" ] ], qs => { active => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", if_primary_term => "number", if_seq_no => "number", version => "number", }, }, 'watcher.query_watches' => { body => {}, doc => "watcher-api-query-watches", parts => {}, paths => [ [ {}, "_watcher", "_query", "watches" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'watcher.start' => { doc => "watcher-api-start", method => "POST", parts => {}, paths => [ [ {}, "_watcher", "_start" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'watcher.stats' => { doc => "watcher-api-stats", parts => { metric => { multi => 1 } }, paths => [ [ { metric => 2 }, "_watcher", "stats", "{metric}" ], [ {}, "_watcher", "stats" ], ], qs => { emit_stacktraces => "boolean", error_trace => "boolean", filter_path => "list", human => "boolean", }, }, 'watcher.stop' => { doc => "watcher-api-stop", method => "POST", parts => {}, paths => [ [ {}, "_watcher", "_stop" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean" }, }, 'xpack.info' => { doc => "info-api", parts => {}, paths => [ [ {}, "_xpack" ] ], qs => { accept_enterprise => "boolean", categories => "list", error_trace => "boolean", filter_path => "list", human => "boolean", }, }, 'xpack.usage' => { doc => "usage-api", parts => {}, paths => [ [ {}, "_xpack", "usage" ] ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", master_timeout => "time", }, }, #=== AUTOGEN - END === ); __PACKAGE__->_qs_init( \%API ); 1; =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Client::7_0::Role::API - This class contains the spec for the Elasticsearch APIs =head1 VERSION version 7.715 =head1 DESCRIPTION All of the Elasticsearch APIs are defined in this role. The example given below is the definition for the L method: 'index' => { body => { required => 1 }, doc => "docs-index_", method => "POST", parts => { id => {}, index => {}, type => {} }, paths => [ [ { id => 2, index => 0, type => 1 }, "{index}", "{type}", "{id}" ], [ { id => 2, index => 0 }, "{index}", "_doc", "{id}" ], [ { index => 0, type => 1 }, "{index}", "{type}" ], [ { index => 0 }, "{index}", "_doc" ], ], qs => { error_trace => "boolean", filter_path => "list", human => "boolean", if_primary_term => "number", if_seq_no => "number", op_type => "enum", pipeline => "string", refresh => "enum", require_alias => "boolean", routing => "string", timeout => "time", version => "number", version_type => "enum", wait_for_active_shards => "string", }, } These definitions can be used by different L implementations to provide distinct user interfaces. =head1 METHODS =head2 C $defn = $api->api($name); The only method in this class is the C method which takes the name of the I and returns its definition. Actions in the C or C namespace use the namespace as a prefix, eg: $defn = $e->api('indices.create'); $defn = $e->api('cluster.node_stats'); =head1 SEE ALSO =over =item * L =item * L =back =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut __END__ # ABSTRACT: This class contains the spec for the Elasticsearch APIs Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Client/7_0/Role/Scroll.pm0000644000175000017500000000553714133761217026076 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::Client::7_0::Role::Scroll; $Search::Elasticsearch::Client::7_0::Role::Scroll::VERSION = '7.715'; use Moo::Role; requires 'finish'; use Search::Elasticsearch::Util qw(parse_params throw); use Devel::GlobalDestruction; use namespace::clean; has 'es' => ( is => 'ro', required => 1 ); has 'scroll' => ( is => 'ro' ); has 'total' => ( is => 'rwp' ); has 'max_score' => ( is => 'rwp' ); has 'facets' => ( is => 'rwp' ); has 'aggregations' => ( is => 'rwp' ); has 'suggest' => ( is => 'rwp' ); has 'took' => ( is => 'rwp' ); has 'total_took' => ( is => 'rwp' ); has 'search_params' => ( is => 'ro' ); has 'is_finished' => ( is => 'rwp', default => '' ); has '_pid' => ( is => 'ro', default => sub {$$} ); has '_scroll_id' => ( is => 'rwp', clearer => 1, predicate => 1 ); #=================================== sub scroll_request { #=================================== my $self = shift; throw( 'Illegal', 'Scroll requests are not fork safe and may only be ' . 'refilled by the same process that created the instance.' ) if $self->_pid != $$; my %args = ( scroll => $self->scroll ); $args{body} = { scroll_id => $self->_scroll_id }; $self->es->scroll(%args); } #=================================== sub DEMOLISH { #=================================== my $self = shift or return; return if in_global_destruction; $self->finish; } 1; # ABSTRACT: Provides common functionality to L and L __END__ =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Client::7_0::Role::Scroll - Provides common functionality to L and L =head1 VERSION version 7.715 =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Client/7_0/Role/Bulk.pm0000644000175000017500000002174514133761217025534 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::Client::7_0::Role::Bulk; $Search::Elasticsearch::Client::7_0::Role::Bulk::VERSION = '7.715'; use Moo::Role; requires 'add_action', 'flush'; use Search::Elasticsearch::Util qw(parse_params throw); use namespace::clean; has 'es' => ( is => 'ro', required => 1 ); has 'max_count' => ( is => 'rw', default => 1_000 ); has 'max_size' => ( is => 'rw', default => 1_000_000 ); has 'max_time' => ( is => 'rw', default => 0 ); has 'on_success' => ( is => 'ro', default => 0 ); has 'on_error' => ( is => 'lazy' ); has 'on_conflict' => ( is => 'ro', default => 0 ); has 'verbose' => ( is => 'rw' ); has '_buffer' => ( is => 'ro', default => sub { [] } ); has '_buffer_size' => ( is => 'rw', default => 0 ); has '_buffer_count' => ( is => 'rw', default => 0 ); has '_serializer' => ( is => 'lazy' ); has '_bulk_args' => ( is => 'ro' ); has '_last_flush' => ( is => 'rw', default => sub {time} ); has '_metadata_params' => ( is => 'ro' ); has '_update_params' => ( is => 'ro' ); has '_required_params' => ( is => 'ro' ); our %Actions = ( 'index' => 1, 'create' => 1, 'update' => 1, 'delete' => 1 ); #=================================== sub _build__serializer { shift->es->transport->serializer } #=================================== #=================================== sub _build_on_error { #=================================== my $self = shift; my $serializer = $self->_serializer; return sub { my ( $action, $result, $src ) = @_; warn( "Bulk error [$action]: " . $serializer->encode($result) ); }; } #=================================== sub BUILDARGS { #=================================== my ( $class, $params ) = parse_params(@_); my $es = $params->{es} or throw( 'Param', 'Missing required param ' ); $params->{_metadata_params} = $es->api('bulk.metadata')->{params}; $params->{_update_params} = $es->api('bulk.update')->{params}; $params->{_required_params} = $es->api('bulk.required')->{params}; my $bulk_spec = $es->api('bulk'); my %args; for ( keys %{ $bulk_spec->{qs} }, keys %{ $bulk_spec->{parts} } ) { $args{$_} = delete $params->{$_} if exists $params->{$_}; } $params->{_bulk_args} = \%args; return $params; } #=================================== sub index { #=================================== shift->add_action( map { ( 'index' => $_ ) } @_ ); } #=================================== sub create { #=================================== shift->add_action( map { ( 'create' => $_ ) } @_ ); } #=================================== sub delete { #=================================== shift->add_action( map { ( 'delete' => $_ ) } @_ ); } #=================================== sub update { #=================================== shift->add_action( map { ( 'update' => $_ ) } @_ ); } #=================================== sub create_docs { #=================================== my $self = shift; $self->add_action( map { ( 'create' => { source => $_ } ) } @_ ); } #=================================== sub delete_ids { #=================================== my $self = shift; $self->add_action( map { ( 'delete' => { _id => $_ } ) } @_ ); } #=================================== sub _encode_action { #=================================== my $self = shift; my $action = shift || ''; my $orig = shift; throw( 'Param', "Unrecognised action <$action>" ) unless $Actions{$action}; throw( 'Param', "Missing for action <$action>" ) unless ref($orig) eq 'HASH'; my %metadata; my $params = {%$orig}; my $serializer = $self->_serializer; my $meta_params = $self->_metadata_params; for ( keys %$meta_params ) { next unless exists $params->{$_}; $metadata{ $meta_params->{$_} } = delete $params->{$_}; } for ( @{ $self->_required_params } ) { throw( 'Param', "Missing required param <$_>" ) unless $metadata{"_$_"} || $self->_bulk_args->{$_}; } my $source; if ( $action eq 'update' ) { for ( @{ $self->_update_params } ) { $source->{$_} = delete $params->{$_} if exists $params->{$_}; } } elsif ( $action ne 'delete' ) { $source = delete $params->{source} || throw( 'Param', "Missing for action <$action>: " . $serializer->encode($orig) ); } throw( "Unknown params <" . ( join ',', sort keys %$params ) . "> in <$action>: " . $serializer->encode($orig) ) if keys %$params; return map { $serializer->encode($_) } grep {$_} ( { $action => \%metadata }, $source ); } #=================================== sub _report { #=================================== my ( $self, $buffer, $results ) = @_; my $on_success = $self->on_success; my $on_error = $self->on_error; my $on_conflict = $self->on_conflict; # assume errors if key not present, bwc $results->{errors} = 1 unless exists $results->{errors}; return unless $on_success || ( $results->{errors} and $on_error || $on_conflict ); my $serializer = $self->_serializer; my $j = 0; for my $item ( @{ $results->{items} } ) { my ( $action, $result ) = %$item; my @args = ($action); if ( my $error = $result->{error} ) { if ($on_conflict) { my ( $is_conflict, $version ) = $self->_is_conflict_error($error); if ($is_conflict) { $on_conflict->( $action, $result, $j, $version ); next; } } $on_error && $on_error->( $action, $result, $j ); } else { $on_success && $on_success->( $action, $result, $j ); } $j++; } } #=================================== sub _is_conflict_error { #=================================== my ( $self, $error ) = @_; my $version; if ( ref($error) eq 'HASH' ) { return 1 if $error->{type} eq 'document_already_exists_exception'; return unless $error->{type} eq 'version_conflict_engine_exception'; $error->{reason} =~ /version.conflict,.current.(?:version.)?\[(\d+)\]/; return ( 1, $1 ); } return unless $error =~ / DocumentAlreadyExistsException |version.conflict,.current.\[(\d+)\] /x; return ( 1, $1 ); } #=================================== sub clear_buffer { #=================================== my $self = shift; @{ $self->_buffer } = (); $self->_buffer_size(0); $self->_buffer_count(0); } #=================================== sub _doc_transformer { #=================================== my ( $self, $params ) = @_; my $bulk_args = $self->_bulk_args; my %allowed = map { $_ => 1, "_$_" => 1 } ( @{ $self->_metadata_params }, 'source' ); $allowed{fields} = 1; delete @allowed{ 'index', '_index' } if $bulk_args->{index}; delete @allowed{ 'type', '_type' } if $bulk_args->{type}; my $version_type = $params->{version_type}; my $transform = $params->{transform}; return sub { my %doc = %{ shift() }; for ( keys %doc ) { delete $doc{$_} unless $allowed{$_}; } if ( my $fields = delete $doc{fields} ) { for (qw(_routing routing _parent parent)) { $doc{$_} = $fields->{$_} if exists $fields->{$_}; } } $doc{_version_type} = $version_type if $version_type; return \%doc unless $transform; return $transform->( \%doc ); }; } 1; # ABSTRACT: Provides common functionality to L and L __END__ =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Client::7_0::Role::Bulk - Provides common functionality to L and L =head1 VERSION version 7.715 =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Client/7_0/Scroll.pm0000644000175000017500000002536014133761217025171 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::Client::7_0::Scroll; $Search::Elasticsearch::Client::7_0::Scroll::VERSION = '7.715'; use Moo; use Search::Elasticsearch::Util qw(parse_params throw); use namespace::clean; has '_buffer' => ( is => 'ro' ); with 'Search::Elasticsearch::Role::Is_Sync', 'Search::Elasticsearch::Client::7_0::Role::Scroll'; #=================================== sub BUILDARGS { #=================================== my ( $class, $params ) = parse_params(@_); my $es = delete $params->{es}; my $scroll = $params->{scroll} ||= '1m'; my $results = $es->search($params); my $total = $results->{hits}{total}; if (ref $total) { $total = $total->{value} } return { es => $es, scroll => $scroll, aggregations => $results->{aggregations}, facets => $results->{facets}, suggest => $results->{suggest}, took => $results->{took}, total_took => $results->{took}, total => $total, max_score => $results->{hits}{max_score}, _buffer => $results->{hits}{hits}, $total ? ( _scroll_id => $results->{_scroll_id} ) : ( is_finished => 1 ) }; } #=================================== sub next { #=================================== my ( $self, $n ) = @_; $n ||= 1; while ( $self->_has_scroll_id and $self->buffer_size < $n ) { $self->refill_buffer; } my @return = splice( @{ $self->_buffer }, 0, $n ); $self->finish if @return < $n; return wantarray ? @return : $return[-1]; } #=================================== sub drain_buffer { #=================================== my $self = shift; return splice( @{ $self->_buffer } ); } #=================================== sub buffer_size { 0 + @{ shift->_buffer } } #=================================== #=================================== sub refill_buffer { #=================================== my $self = shift; return 0 if $self->is_finished; my $buffer = $self->_buffer; my $scroll_id = $self->_scroll_id || return 0 + @$buffer; my $results = $self->scroll_request; my $hits = $results->{hits}{hits}; $self->_set_total_took( $self->total_took + $results->{took} ); if ( @$hits == 0 ) { $self->_clear_scroll_id; } else { $self->_set__scroll_id( $results->{_scroll_id} ); push @$buffer, @$hits; } $self->finish if @$buffer == 0; return 0 + @$buffer; } #=================================== sub finish { #=================================== my $self = shift; return if $self->is_finished || $self->_pid != $$; $self->_set_is_finished(1); @{ $self->_buffer } = (); my $scroll_id = $self->_scroll_id or return; $self->_clear_scroll_id; my %args = ( body => { scroll_id => $scroll_id } ); eval { $self->es->clear_scroll(%args) }; return 1; } 1; =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Client::7_0::Scroll - A helper module for scrolled searches =head1 VERSION version 7.715 =head1 SYNOPSIS use Search::Elasticsearch; my $es = Search::Elasticsearch->new; my $scroll = $es->scroll_helper( index => 'my_index', body => { query => {...}, size => 1000, sort => '_doc' } ); say "Total hits: ". $scroll->total; while (my $doc = $scroll->next) { # do something } =head1 DESCRIPTION A I is a search that allows you to keep pulling results until there are no more matching results, much like a cursor in an SQL database. Unlike paginating through results (with the C parameter in L), scrolled searches take a snapshot of the current state of the index. Even if you keep adding new documents to the index or updating existing documents, a scrolled search will only see the index as it was when the search began. This module is a helper utility that wraps the functionality of the L and L methods to make them easier to use. This class does L and L. =head1 USE CASES There are two primary use cases: =head2 Pulling enough results Perhaps you want to group your results by some field, and you don't know exactly how many results you will need in order to return 10 grouped results. With a scrolled search you can keep pulling more results until you have enough. For instance, you can search emails in a mailing list, and return results grouped by C: my (%groups,@results); my $scroll = $es->scroll_helper( index => 'my_emails', type => 'email', body => { query => {... some query ... }} ); my $doc; while (@results < 10 and $doc = $scroll->next) { my $thread = $doc->{_source}{thread_id}; unless ($groups{$thread}) { $groups{$thread} = []; push @results, $groups{$thread}; } push @{$groups{$thread}},$doc; } =head2 Extracting all documents Often you will want to extract all (or a subset of) documents in an index. If you want to change your type mappings, you will need to reindex all of your data. Or perhaps you want to move a subset of the data in one index into a new dedicated index. In these cases, you don't care about sort order, you just want to retrieve all documents which match a query, and do something with them. For instance, to retrieve all the docs for a particular C: my $scroll = $es->scroll_helper( index => 'my_index', size => 1000, body => { query => { match => { client_id => 123 } }, sort => '_doc' } ); while (my $doc = $scroll->next) { # do something } Very often the I that you will want to do with these results involves bulk-indexing them into a new index. The easiest way to do this is to use the built-in L functionality provided by Elasticsearch. =head1 METHODS =head2 C use Search::Elasticsearch; my $es = Search::Elasticsearch->new(...); my $scroll = $es->scroll_helper( scroll => '1m', # optional %search_params ); The L method loads L class and calls L, passing in any arguments. You can specify a C duration (which defaults to C<"1m">). Any other parameters are passed directly to L. The C duration tells Elasticearch how long it should keep the scroll alive. B: this duration doesn't need to be long enough to process all results, just long enough to process a single B of results. The expiry gets renewed for another C period every time new a new batch of results is retrieved from the cluster. By default, the C is passed as the C to the L request. The C request uses C by default. To use C instead, set L to C. =head2 C $doc = $scroll->next; @docs = $scroll->next($num); The C method returns the next result, or the next C<$num> results (pulling more results if required). If all results have been exhausted, it returns an empty list. =head2 C @docs = $scroll->drain_buffer; The C method returns all of the documents currently in the buffer, without fetching any more from the cluster. =head2 C $total = $scroll->refill_buffer; The C method fetches the next batch of results from the cluster, stores them in the buffer, and returns the total number of docs currently in the buffer. =head2 C $total = $scroll->buffer_size; The C method returns the total number of docs currently in the buffer. =head2 C $scroll->finish; The C method clears out the buffer, sets L to C and tries to clear the C on Elasticsearch. This API is only supported since v0.90.6, but the call to C is wrapped in an C so the C method can be safely called with any version of Elasticsearch. When the C<$scroll> instance goes out of scope, L is called automatically if required. =head2 C $bool = $scroll->is_finished; A flag which returns C if all results have been processed or L has been called. =head1 INFO ACCESSORS The information from the original search is returned via the following accessors: =head2 C The total number of documents that matched your query. =head2 C The maximum score of any documents in your query. =head2 C Any aggregations that were specified, or C =head2 C Any facets that were specified, or C =head2 C Any suggestions that were specified, or C =head2 C How long the original search took, in milliseconds =head2 C How long the original search plus all subsequent batches took, in milliseconds. =head1 SEE ALSO =over =item * L =item * L =item * L =back =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut __END__ # ABSTRACT: A helper module for scrolled searches Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Client/7_0/Direct.pm0000644000175000017500000013534114133761217025146 0ustar enricoenrico# Licensed to Elasticsearch B.V under one or more agreements. # Elasticsearch B.V licenses this file to you under the Apache 2.0 License. # See the LICENSE file in the project root for more information package Search::Elasticsearch::Client::7_0::Direct; $Search::Elasticsearch::Client::7_0::Direct::VERSION = '7.715'; use Moo; with 'Search::Elasticsearch::Client::7_0::Role::API'; with 'Search::Elasticsearch::Role::Client::Direct'; use Search::Elasticsearch::Util qw(parse_params is_compat); use namespace::clean; sub _namespace {__PACKAGE__} has 'async_search' => ( is => 'lazy', init_arg => undef ); has 'autoscaling' => ( is => 'lazy', init_arg => undef ); has 'cat' => ( is => 'lazy', init_arg => undef ); has 'ccr' => ( is => 'lazy', init_arg => undef ); has 'cluster' => ( is => 'lazy', init_arg => undef ); has 'dangling_indices' => ( is => 'lazy', init_arg => undef ); has 'data_frame_transform_deprecated' => ( is => 'lazy', init_arg => undef ); has 'enrich' => ( is => 'lazy', init_arg => undef ); has 'eql' => ( is => 'lazy', init_arg => undef ); has 'features' => ( is => 'lazy', init_arg => undef ); has 'fleet' => ( is => 'lazy', init_arg => undef ); has 'graph' => ( is => 'lazy', init_arg => undef ); has 'ilm' => ( is => 'lazy', init_arg => undef ); has 'indices' => ( is => 'lazy', init_arg => undef ); has 'ingest' => ( is => 'lazy', init_arg => undef ); has 'license' => ( is => 'lazy', init_arg => undef ); has 'logstash' => ( is => 'lazy', init_arg => undef ); has 'migration' => ( is => 'lazy', init_arg => undef ); has 'ml' => ( is => 'lazy', init_arg => undef ); has 'monitoring' => ( is => 'lazy', init_arg => undef ); has 'nodes' => ( is => 'lazy', init_arg => undef ); has 'rollup' => ( is => 'lazy', init_arg => undef ); has 'searchable_snapshots' => ( is => 'lazy', init_arg => undef ); has 'security' => ( is => 'lazy', init_arg => undef ); has 'shutdown' => ( is => 'lazy', init_arg => undef ); has 'snapshot' => ( is => 'lazy', init_arg => undef ); has 'slm' => ( is => 'lazy', init_arg => undef ); has 'sql' => ( is => 'lazy', init_arg => undef ); has 'ssl' => ( is => 'lazy', init_arg => undef ); has 'tasks' => ( is => 'lazy', init_arg => undef ); has 'text_structure' => ( is => 'lazy', init_arg => undef ); has 'transform' => ( is => 'lazy', init_arg => undef ); has 'watcher' => ( is => 'lazy', init_arg => undef ); has 'xpack' => ( is => 'lazy', init_arg => undef ); has 'bulk_helper_class' => ( is => 'rw' ); has 'scroll_helper_class' => ( is => 'rw' ); has '_bulk_class' => ( is => 'lazy' ); has '_scroll_class' => ( is => 'lazy' ); #=================================== sub _build__bulk_class { #=================================== my $self = shift; my $bulk_class = $self->bulk_helper_class || 'Client::' . $self->api_version . '::Bulk'; $self->_build_helper( 'bulk', $bulk_class ); } #=================================== sub _build__scroll_class { #=================================== my $self = shift; my $scroll_class = $self->scroll_helper_class || 'Client::' . $self->api_version . '::Scroll'; $self->_build_helper( 'scroll', $scroll_class ); } #=================================== sub bulk_helper { #=================================== my ( $self, $params ) = parse_params(@_); $params->{es} ||= $self; $self->_bulk_class->new($params); } #=================================== sub scroll_helper { #=================================== my ( $self, $params ) = parse_params(@_); $params->{es} ||= $self; $self->_scroll_class->new($params); } #=================================== sub _build_autoscaling { shift->_build_namespace('Autoscaling') } sub _build_async_search { shift->_build_namespace('AsyncSearch') } sub _build_cat { shift->_build_namespace('Cat') } sub _build_ccr { shift->_build_namespace('CCR') } sub _build_cluster { shift->_build_namespace('Cluster') } sub _build_dangling_indices { shift->_build_namespace('DanglingIndices') } sub _build_data_frame_transform_deprecated { shift->_build_namespace('DataFrameTransformDeprecated') } sub _build_enrich { shift->_build_namespace('Enrich') } sub _build_eql { shift->_build_namespace('Eql') } sub _build_features { shift->_build_namespace('Features') } sub _build_fleet { shift->_build_namespace('Fleet') } sub _build_graph { shift->_build_namespace('Graph') } sub _build_ilm { shift->_build_namespace('ILM') } sub _build_indices { shift->_build_namespace('Indices') } sub _build_ingest { shift->_build_namespace('Ingest') } sub _build_license { shift->_build_namespace('License') } sub _build_logstash { shift->_build_namespace('Logstash') } sub _build_migration { shift->_build_namespace('Migration') } sub _build_ml { shift->_build_namespace('ML') } sub _build_monitoring { shift->_build_namespace('Monitoring') } sub _build_nodes { shift->_build_namespace('Nodes') } sub _build_rollup { shift->_build_namespace('Rollup') } sub _build_searchable_snapshots { shift->_build_namespace('SearchableSnapshots') } sub _build_security { shift->_build_namespace('Security') } sub _build_shutdown { shift->_build_namespace('Shutdown') } sub _build_snapshot { shift->_build_namespace('Snapshot') } sub _build_slm { shift->_build_namespace('Slm') } sub _build_sql { shift->_build_namespace('SQL') } sub _build_ssl { shift->_build_namespace('SSL') } sub _build_tasks { shift->_build_namespace('Tasks') } sub _build_text_structure { shift->_build_namespace('TextStructure') } sub _build_transform { shift->_build_namespace('Transform') } sub _build_watcher { shift->_build_namespace('Watcher') } sub _build_xpack { shift->_build_namespace('XPack') } #=================================== __PACKAGE__->_install_api(''); 1; =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Client::7_0::Direct - Thin client with full support for Elasticsearch 7.x APIs =head1 VERSION version 7.715 =head1 SYNOPSIS Create a client: use Search::Elasticsearch; my $e = Search::Elasticsearch->new( client => '7_0::Direct' ); Index a doc: $e->index( index => 'my_index', type => 'blog_post', id => 123, body => { title => "Elasticsearch clients", content => "Interesting content...", date => "2013-09-23" } ); Get a doc: $e->get( index => 'my_index', type => 'my_type', id => 123 ); Search for docs: $results = $e->search( index => 'my_index', body => { query => { match => { title => "elasticsearch" } } } ); Index-level requests: $e->indices->create( index => 'my_index' ); $e->indices->delete( index => 'my_index' ) Ingest pipeline requests: $e->ingest->get_pipeline( id => 'apache-logs' ); Cluster-level requests: $health = $e->cluster->health; Node-level requests: $info = $e->nodes->info; $stats = $e->nodes->stats; Snapshot and restore: $e->snapshot->create_repository( repository => 'my_backups', type => 'fs', settings => { location => '/mnt/backups' } ); $e->snapshot->create( repository => 'my_backups', snapshot => 'backup_2014' ); Task management: $e->tasks->list; `cat` debugging: say $e->cat->allocation; say $e->cat->health; Cross-cluster replication requests: say $e->ccr->follow; Index lifecycle management requests: say $e->ilm->put_lifecycle; =head1 DESCRIPTION The L class provides the Elasticsearch 7.x compatible client returned by: $e = Search::Elasticsearch->new( client => "7_0::Direct" # default ); It is intended to be as close as possible to the native REST API that Elasticsearch uses, so that it is easy to translate the L for an API to the equivalent in this client. This class provides the methods for L, L and L. It also provides access to clients for managing L and the L. =head1 PREVIOUS VERSIONS OF ELASTICSEARCH This version of the client supports the Elasticsearch 7.0 branch, which is not backwards compatible with earlier branches. If you need to talk to a version of Elasticsearch before 7.0.0, please install one of the following modules: =over =item * L =item * L =item * L =item * L =item * L =back =head1 CONVENTIONS =head2 Parameter passing Parameters can be passed to any request method as a list or as a hash reference. The following two statements are equivalent: $e->search( size => 10 ); $e->search({size => 10}); =head2 Path parameters Any values that should be included in the URL path, eg C should be passed as top level parameters: $e->search( index => 'my_index', type => 'my_type' ); Alternatively, you can specify a C parameter directly: $e->search( path => '/my_index/my_type' ); =head2 Query-string parameters Any values that should be included in the query string should be passed as top level parameters: $e->search( size => 10 ); If you pass in a C<\%params> hash, then it will be included in the query string parameters without any error checking. The following: $e->search( size => 10, params => { from => 6, size => 6 }) would result in this query string: ?from=6&size=10 =head2 Body parameter The request body should be passed in the C key: $e->search( body => { query => {...} } ); The body can also be a UTF8-decoded string, which will be converted into UTF-8 bytes and passed as is: $e->indices->analyze( body => "The quick brown fox"); =head2 Boolean parameters Elasticsearch 7.0.0 and above no longer accepts truthy and falsey values for booleans. Instead, it will accept only a JSON C or C, or the string equivalents C<"true"> or C<"false">. In the Perl client, you can use the following values: =over =item * True: C, C<\1>, or a L object. =item * False: C, C<\0>, or a L object. =back =head2 Filter path parameter Any API which returns a JSON body accepts a C parameter which will filter the JSON down to only the specified paths. For instance, if you are running a search request and only want the C hits and the C<_source> field for each hit (without the C<_id>, C<_index> etc), you can do: $e->search( query => {...}, filter_paths => [ 'hits.total', 'hits.hits._source' ] ); =head2 Ignore parameter Normally, any HTTP status code outside the 200-299 range will result in an error being thrown. To suppress these errors, you can specify which status codes to ignore in the C parameter. $e->indices->delete( index => 'my_index', ignore => 404 ); This is most useful for L errors, which are triggered by a C<404> status code when some requested resource does not exist. Multiple error codes can be specified with an array: $e->indices->delete( index => 'my_index', ignore => [404,409] ); =head1 CONFIGURATION =head2 C The class to use for the L method. Defaults to L. =head2 C The class to use for the L method. Defaults to L. =head1 GENERAL METHODS =head2 C $info = $e->info Returns information about the version of Elasticsearch that the responding node is running. =head2 C $e->ping Pings a node in the cluster and returns C<1> if it receives a C<200> response, otherwise it throws an error. =head2 C $indices_client = $e->indices; Returns a L object which can be used for managing indices, eg creating, deleting indices, managing mapping, index settings etc. =head2 C $ingest_client = $e->ingest; Returns a L object which can be used for managing ingest pipelines. =head2 C $cluster_client = $e->cluster; Returns a L object which can be used for managing the cluster, eg cluster-wide settings and cluster health. =head2 C $node_client = $e->nodes; Returns a L object which can be used to retrieve node info and stats. =head2 C $snapshot_client = $e->snapshot; Returns a L object which is used for managing backup repositories and creating and restoring snapshots. =head2 C $tasks_client = $e->tasks; Returns a L object which is used for accessing the task management API. =head2 C $cat_client = $e->cat; Returns a L object which can be used to retrieve simple to read text info for debugging and monitoring an Elasticsearch cluster. =head2 C $ccr_client = $e->ccr; Returns a L object which can be used to handle cross-cluster replication requests. =head2 C $ilm_client = $e->ilm; Returns a L object which can be used to handle index lifecycle management requests. =head1 DOCUMENT CRUD METHODS These methods allow you to perform create, index, update and delete requests for single documents: =head2 C $response = $e->index( index => 'index_name', # required type => 'type_name', # required id => 'doc_id', # optional, otherwise auto-generated body => { document } # required ); The C method is used to index a new document or to reindex an existing document. Query string parameters: C, C, C, C, C, C, C, C, C, C, C, C, C See the L for more information. =head2 C $response = $e->create( index => 'index_name', # required type => 'type_name', # required id => 'doc_id', # required body => { document } # required ); The C method works exactly like the L method, except that it will throw a C error if a document with the same C, C and C already exists. Query string parameters: C, C, C, C, C, C, C, C, C, C See the L for more information. =head2 C $response = $e->get( index => 'index_name', # required type => 'type_name', # required id => 'doc_id', # required ); The C method will retrieve the document with the specified C, C and C, or will throw a C error. Query string parameters: C<_source>, C<_source_excludes>, C<_source_includes>, C, C, C, C, C, C, C, C, C, C See the L for more information. =head2 C $response = $e->get_source( index => 'index_name', # required type => 'type_name', # required id => 'doc_id', # required ); The C method works just like the L method except that it returns just the C<_source> field (the value of the C parameter in the L method) instead of returning the C<_source> field plus the document metadata, ie the C<_index>, C<_type> etc. Query string parameters: C<_source>, C<_source_excludes>, C<_source_includes>, C, C, C, C, C, C, C, C, C See the L for more information. =head2 C $response = $e->exists( index => 'index_name', # required type => 'type_name', # required id => 'doc_id', # required ); The C method returns C<1> if a document with the specified C, C and C exists, or an empty string if it doesn't. Query string parameters: C<_source>, C<_source_excludes>, C<_source_includes>, C, C, C, C, C, C, C, C, C See the L for more information. =head2 C $response = $e->delete( index => 'index_name', # required type => 'type_name', # required id => 'doc_id', # required ); The C method will delete the document with the specified C, C and C, or will throw a C error. Query string parameters: C, C, C, C, C, C, C, C, C, C, C See the L for more information. =head2 C $response = $e->update( index => 'index_name', # required type => 'type_name', # required id => 'doc_id', # required body => { update } # required ); The C method updates a document with the corresponding C, C and C if it exists. Updates can be performed either by: =over =item * providing a partial document to be merged in to the existing document: $response = $e->update( ..., body => { doc => { new_field => 'new_value'}, } ); =item * with an inline script: $response = $e->update( ..., body => { script => { source => "ctx._source.counter += incr", params => { incr => 6 } } } ); =item * with an indexed script: $response = $e->update( ..., body => { script => { id => $id, lang => 'painless', params => { incr => 6 } } } ); See L for more information. =item * with a script stored as a file: $response = $e->update( ..., body => { script => { file => 'counter', lang => 'painless', params => { incr => 6 } } } ); See L for more information. =back Query string parameters: C<_source>, C<_source_excludes>, C<_source_includes>, C, C, C, C, C, C, C, C, C, C, C, C, C, C See the L for more information. =head2 C $results = $e->termvectors( index => $index, # required type => $type, # required id => $id, # optional body => {...} # optional ) The C method retrieves term and field statistics, positions, offsets and payloads for the specified document, assuming that termvectors have been enabled. Query string parameters: C, C, C, C, C, C, C, C, C, C, C, C, C, C See the L for more information. =head1 BULK DOCUMENT CRUD METHODS The bulk document CRUD methods are used for running multiple CRUD actions within a single request. By reducing the number of network requests that need to be made, bulk requests greatly improve performance. =head2 C $response = $e->bulk( index => 'index_name', # required if type specified type => 'type_name', # optional body => [ actions ] # required ); See L and L for a helper module that makes bulk indexing simpler to use. The C method can perform multiple L, L, L or L actions with a single request. The C parameter expects an array containing the list of actions to perform. An I consists of an initial metadata hash ref containing the action type, plus the associated metadata, eg : { delete => { _index => 'index', _type => 'type', _id => 123 }} The C and C actions then expect a hashref containing the document itself: { create => { _index => 'index', _type => 'type', _id => 123 }}, { title => "A newly created document" } And the C action expects a hashref containing the update commands, eg: { update => { _index => 'index', _type => 'type', _id => 123 }}, { script => "ctx._source.counter+=1" } Each action can include the same parameters that you would pass to the equivalent L, L, L or L request, except that C<_index>, C<_type> and C<_id> must be specified with the preceding underscore. All other parameters can be specified with or without the underscore. For instance: $response = $e->bulk( index => 'index_name', # default index name type => 'type_name', # default type name body => [ # create action { create => { _index => 'not_the_default_index', _type => 'not_the_default_type', _id => 123 }}, { title => 'Foo' }, # index action { index => { _id => 124 }}, { title => 'Foo' }, # delete action { delete => { _id => 126 }}, # update action { update => { _id => 126 }}, { script => "ctx._source.counter+1" } ] ); Each action is performed separately. One failed action will not cause the others to fail as well. Query string parameters: C<_source>, C<_source_excludes>, C<_source_includes>, C, C, C, C, C, C, C, C See the L for more information. =head2 C $bulk_helper = $e->bulk_helper( @args ); Returns a new instance of the class specified in the L, which defaults to L. =head2 C $results = $e->mget( index => 'default_index', # optional, required when type specified type => 'default_type', # optional body => { docs or ids } # required ); The C method will retrieve multiple documents with a single request. The C consists of an array of documents to retrieve: $results = $e->mget( index => 'default_index', type => 'default_type', body => { docs => [ { _id => 1}, { _id => 2, _type => 'not_the_default_type' } ] } ); You can also pass any of the other parameters that the L request accepts. If you have specified an C and C, you can just include the C of the documents to retrieve: $results = $e->mget( index => 'default_index', type => 'default_type', body => { ids => [ 1, 2, 3] } ); Query string parameters: C<_source>, C<_source_excludes>, C<_source_includes>, C, C, C, C, C, C, C See the L for more information. =head2 C $results = $e->mtermvectors( index => $index, # required if type specified type => $type, # optional body => { } # optional ) Runs multiple L requests in a single request, eg: $results = $e->mtermvectors( index => 'test', body => { docs => [ { _type => 'test', _id => 1, fields => ['text'] }, { _type => 'test', _id => 2, payloads => 1 }, ] } ); Query string parameters: C, C, C, C, C, C, C, C, C, C, C, C, C, C, C See the L for more information. =head1 SEARCH METHODS The search methods are used for querying documents in one, more or all indices and of one, more or all types: =head2 C $results = $e->search( index => 'index' | \@indices, # optional type => 'type' | \@types, # optional body => { search params } # optional ); The C method searches for matching documents in one or more indices. It is just as easy to search a single index as it is to search all the indices in your cluster. It can also return L L and L or L suggestions. The I L allows you to specify a query string in the C parameter, using the Lucene query string syntax: $results = $e->search( q => 'title:(elasticsearch clients)'); However, the preferred way to search is by using the L to create a query, and passing that C in the L: $results = $e->search( body => { query => { match => { title => 'Elasticsearch clients'} } } ); Query string parameters: C<_source>, C<_source_excludes>, C<_source_includes>, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C See the L for more information. Also see L. =head2 C $results = $e->count( index => 'index' | \@indices, # optional type => 'type' | \@types, # optional body => { query } # optional ) The C method returns the total count of all documents matching the query: $results = $e->count( body => { query => { match => { title => 'Elasticsearch clients' } } } ); Query string parameters: C, C, C, C, C, C, C, C, C, C, C, C C, C, C, C, C See the L for more information. =head2 C $results = $e->search_template( index => 'index' | \@indices, # optional type => 'type' | \@types, # optional body => { search params } # required ); Perform a search by specifying a template (either predefined or defined within the C) and parameters to use with the template, eg: $results = $e->search_template( body => { source => { query => { match => { "{{my_field}}" => "{{my_value}}" } }, size => "{{my_size}}" }, params => { my_field => 'foo', my_value => 'bar', my_size => 6 } } ); See the L for more information. Query string parameters: C, C, C, C, C, C, C, C, C, C, C, C, C =head2 C $response = $e->render_search_template( id => 'id', # optional body => { template } # optional ); Renders the template, filling in the passed-in parameters and returns the resulting JSON, eg: $results = $e->render_search_template( body => { source => { query => { match => { "{{my_field}}" => "{{my_value}}" } }, size => "{{my_size}}" }, params => { my_field => 'foo', my_value => 'bar', my_size => 6 } } ); See the L for more information. =head2 C $results = $e->scroll( scroll => '1m', body => { scroll_id => $id } ); When a L has been performed with the C parameter, the C method allows you to keep pulling more results until the results are exhausted. See L and L for a helper utility which makes managing scroll requests much easier. Query string parameters: C, C, C, C, C See the L and the L for more information. =head2 C $response = $e->clear_scroll( body => { scroll_id => $id | \@ids # required } ); The C method can clear unfinished scroll requests, freeing up resources on the server. =head2 C $scroll_helper = $e->scroll_helper( @args ); Returns a new instance of the class specified in the L, which defaults to L. =head2 C $results = $e->msearch( index => 'default_index' | \@indices, # optional type => 'default_type' | \@types, # optional body => [ searches ] # required ); The C method allows you to perform multiple searches in a single request. Similar to the L request, each search request in the C consists of two hashes: the metadata hash then the search request hash (the same data that you'd specify in the C of a L request). For instance: $results = $e->msearch( index => 'default_index', type => ['default_type_1', 'default_type_2'], body => [ # uses defaults {}, { query => { match_all => {} }}, # uses a custom index { index => 'not_the_default_index' }, { query => { match_all => {} }} ] ); Query string parameters: C, C, C, C, C, C, C, C See the L for more information. =head2 C $results = $e->msearch_template( index => 'default_index' | \@indices, # optional type => 'default_type' | \@types, # optional body => [ search_templates ] # required ); The C method allows you to perform multiple searches in a single request using search templates. Similar to the L request, each search request in the C consists of two hashes: the metadata hash then the search request hash (the same data that you'd specify in the C of a L request). For instance: $results = $e->msearch( index => 'default_index', type => ['default_type_1', 'default_type_2'], body => [ # uses defaults {}, { source => { query => { match => { user => "{{user}}" }}} params => { user => 'joe' }}, # uses a custom index { index => 'not_the_default_index' }, { source => { query => { match => { user => "{{user}}" }}} params => { user => 'joe' }}, ] ); Query string parameters: C, C, C, C, C, C See the L for more information. =head2 C $response = $e->explain( index => 'my_index', # required type => 'my_type', # required id => 123, # required body => { search } # required ); The C method explains why the specified document did or did not match a query, and how the relevance score was calculated. For instance: $response = $e->explain( index => 'my_index', type => 'my_type', id => 123, body => { query => { match => { title => 'Elasticsearch clients' } } } ); Query string parameters: C<_source>, C<_source_excludes>, C<_source_includes>, C, C, C, C, C, C, C, C, C, C, C, C See the L for more information. =head2 C $response = $e->field_caps( index => 'index' | \@indices, # optional body => { filters } # optional ); The C API returns field types and abilities, merged across indices. Query string parameters: C, C, C, C, C, C See the L for more information. =head2 C $response = $e->search_shards( index => 'index' | \@indices, # optional ) The C method returns information about which shards on which nodes will execute a search request. Query string parameters: C, C, C, C, C, C, C, C See the L for more information. =head2 C $result = $e->rank_eval( index => 'index' | \@indices, # optional body => {...} # required ); The ranking evaluation API provides a way to execute test cases to determine whether search results are improving or worsening. Query string parameters: C, C, C, C, C, C See the L for more information. =head1 CRUD-BY-QUERY METHODS =head2 C $response = $e->delete_by_query( index => 'index' | \@indices, # optional type => 'type' | \@types, # optional, body => { delete-by-query } # required ); The C method deletes all documents which match the specified query. Query string parameters: C<_source>, C<_source_excludes>, C<_source_includes>, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C See the L for more information. =head2 C $response = $e->delete_by_query_rethrottle( task_id => 'id' # required requests_per_second => num ); The C API is used to dynamically update the throtting of an existing delete-by-query request, identified by C. Query string parameters: C, C, C, C See the L for more information. =head2 C $response = $e->reindex( body => { reindex } # required ); The C API is used to index documents from one index or multiple indices to a new index. Query string parameters: C, C, C, C, C, C, C, C See the L for more information. =head2 C $response = $e->delete_by_query_rethrottle( task_id => 'id', # required requests_per_second => num ); The C API is used to dynamically update the throtting of an existing reindex request, identified by C. Query string parameters: C, C, C, C See the L for more information. =head2 C $response = $e->update_by_query( index => 'index' | \@indices, # optional type => 'type' | \@types, # optional, body => { update-by-query } # optional ); The C API is used to bulk update documents from one index or multiple indices using a script. Query string parameters: C<_source>, C<_source_excludes>, C<_source_includes>, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C See the L for more information. =head2 C $response = $e->update_by_query_rethrottle( task_id => 'id' # required requests_per_second => num ); The C API is used to dynamically update the throtting of an existing update-by-query request, identified by C. Query string parameters: C, C, C, C See the L for more information. =head1 INDEXED SCRIPT METHODS Elasticsearch allows you to store scripts in the cluster state and reference them by id. The methods to manage indexed scripts are as follows: =head2 C $result = $e->put_script( id => 'id', # required context => $context, # optional body => { script } # required ); The C method is used to store a script in the cluster state. For instance: $result = $e->put_scripts( id => 'hello_world', body => { script => { lang => 'painless', source => q(return "hello world") } } ); Query string parameters: C, C See the L for more. =head2 C $script = $e->get_script( id => 'id', # required ); Retrieve the indexed script from the cluster state. Query string parameters: C, C, C See the L for more. =head2 C $script = $e->delete_script( id => 'id', # required ); Delete the indexed script from the cluster state. Query string parameters: C, C, C, C See the L for more. =head2 C $result = $e->scripts_painless_execute( body => {...} # required ); The Painless execute API allows an arbitrary script to be executed and a result to be returned. Query string parameters: C, C, C See the L for more. =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut __END__ # ABSTRACT: Thin client with full support for Elasticsearch 7.x APIs Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Client/7_0/TestServer.pm0000644000175000017500000000402614133761217026035 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::Client::7_0::TestServer; $Search::Elasticsearch::Client::7_0::TestServer::VERSION = '7.715'; use strict; use warnings; #=================================== sub command_line { #=================================== my ( $class, $ts, $pid_file, $dir, $transport, $http ) = @_; return ( $ts->es_home . '/bin/elasticsearch', '-p', $pid_file->filename, map {"-E$_"} ( 'path.data=' . $dir, 'network.host=127.0.0.1', 'cluster.name=es_test', 'discovery.zen.ping_timeout=1s', 'discovery.zen.ping.unicast.hosts=127.0.0.1:' . $ts->es_port, 'transport.tcp.port=' . $transport, 'http.port=' . $http, @{ $ts->conf } ) ); } 1 # ABSTRACT: Client-specific backend for Search::Elasticsearch::TestServer __END__ =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Client::7_0::TestServer - Client-specific backend for Search::Elasticsearch::TestServer =head1 VERSION version 7.715 =head1 AUTHOR Enrico Zimuel =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2021 by Elasticsearch BV. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut Search-Elasticsearch-7.715/lib/Search/Elasticsearch/Client/7_0/Bulk.pm0000644000175000017500000003133414133761217024626 0ustar enricoenrico# Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright # ownership. Elasticsearch B.V. licenses this file to you under # the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. package Search::Elasticsearch::Client::7_0::Bulk; $Search::Elasticsearch::Client::7_0::Bulk::VERSION = '7.715'; use Moo; with 'Search::Elasticsearch::Client::7_0::Role::Bulk', 'Search::Elasticsearch::Role::Is_Sync'; use Search::Elasticsearch::Util qw(parse_params throw); use Try::Tiny; use namespace::clean; #=================================== sub add_action { #=================================== my $self = shift; my $buffer = $self->_buffer; my $max_size = $self->max_size; my $max_count = $self->max_count; my $max_time = $self->max_time; while (@_) { my @json = $self->_encode_action( splice( @_, 0, 2 ) ); push @$buffer, @json; my $size = $self->_buffer_size; $size += length($_) + 1 for @json; $self->_buffer_size($size); my $count = $self->_buffer_count( $self->_buffer_count + 1 ); $self->flush if ( $max_size and $size >= $max_size ) || ( $max_count and $count >= $max_count ) || ( $max_time and time >= $self->_last_flush + $max_time ); } return 1; } #=================================== sub flush { #=================================== my $self = shift; $self->_last_flush(time); return { items => [] } unless $self->_buffer_size; if ( $self->verbose ) { local $| = 1; print "."; } my $buffer = $self->_buffer; my $results = try { my $res = $self->es->bulk( %{ $self->_bulk_args }, body => $buffer ); $self->clear_buffer; return $res; } catch { my $error = $_; $self->clear_buffer unless $error->is( 'Cxn', 'NoNodes' ); die $error; }; $self->_report( $buffer, $results ); return defined wantarray ? $results : undef; } 1; =pod =encoding UTF-8 =head1 NAME Search::Elasticsearch::Client::7_0::Bulk - A helper module for the Bulk API =head1 VERSION version 7.715 =head1 SYNOPSIS use Search::Elasticsearch; my $es = Search::Elasticsearch->new; my $bulk = $es->bulk_helper( index => 'my_index', type => 'my_type' ); # Index docs: $bulk->index({ id => 1, source => { foo => 'bar' }}); $bulk->add_action( index => { id => 1, source => { foo=> 'bar' }}); # Create docs: $bulk->create({ id => 1, source => { foo => 'bar' }}); $bulk->add_action( create => { id => 1, source => { foo=> 'bar' }}); $bulk->create_docs({ foo => 'bar' }) # Delete docs: $bulk->delete({ id => 1}); $bulk->add_action( delete => { id => 1 }); $bulk->delete_ids(1,2,3) # Update docs: $bulk->update({ id => 1, script => '...' }); $bulk->add_action( update => { id => 1, script => '...' }); # Manual flush $bulk->flush; =head1 DESCRIPTION This module provides a wrapper for the L method which makes it easier to run multiple create, index, update or delete actions in a single request. The L module acts as a queue, buffering up actions until it reaches a maximum count of actions, or a maximum size of JSON request body, at which point it issues a C request. Once you have finished adding actions, call L to force the final C request on the items left in the queue. This class does L and L. =head1 CREATING A NEW INSTANCE =head2 C my $bulk = $es->bulk_helper( index => 'default_index', # optional type => 'default_type', # optional %other_bulk_params # optional max_count => 1_000, # optional max_size => 1_000_000, # optional max_time => 6, # optional verbose => 0 | 1, # optional on_success => sub {...}, # optional on_error => sub {...}, # optional on_conflict => sub {...}, # optional ); The C method returns a new C<$bulk> object. You must pass your Search::Elasticsearch client as the C argument. The C and C parameters provide default values for C and C, which can be overridden in each action. You can also pass any other values which are accepted by the L method. See L for more information about the other parameters. =head1 FLUSHING THE BUFFER =head2 C $result = $bulk->flush; The C method sends all buffered actions to Elasticsearch using a L request. =head2 Auto-flushing An automatic L is triggered whenever the C, C, or C threshold is breached. This causes all actions in the buffer to be sent to Elasticsearch. =over =item * C The maximum number of actions to allow before triggering a L. This can be disabled by setting C to C<0>. Defaults to C<1,000>. =item * C The maximum size of JSON request body to allow before triggering a L. This can be disabled by setting C to C<0>. Defaults to C<1_000,000> bytes. =item * C The maximum number of seconds to wait before triggering a flush. Defaults to C<0> seconds, which means that it is disabled. B This timeout is only triggered when new items are added to the queue, not in the background. =back =head2 Errors when flushing There are two types of error which can be thrown when L is called, either manually or automatically. =over =item * Temporary Elasticsearch errors A C error like a C error which indicates that your cluster is down. These errors do not clear the buffer, as they can be retried later on. =item * Action errors Individual actions may fail. For instance, a C action will fail if a document with the same C, C and C already exists. These action errors are reported via L. =back =head2 Using callbacks By default, any I (see above) cause warnings to be written to C. However, you can use the C, C and C callbacks for more fine-grained control. All callbacks receive the following arguments: =over =item C<$action> The name of the action, ie C, C, C or C. =item C<$response> The response that Elasticsearch returned for this action. =item C<$i> The index of the action, ie the first action in the flush request will have C<$i> set to C<0>, the second will have C<$i> set to C<1> etc. =back =head3 C my $bulk = $es->bulk_helper( on_success => sub { my ($action,$response,$i) = @_; # do something }, ); The C callback is called for every action that has a successful response. =head3 C my $bulk = $es->bulk_helper( on_conflict => sub { my ($action,$response,$i,$version) = @_; # do something }, ); The C callback is called for actions that have triggered a C error, eg trying to C a document which already exists. The C<$version> argument will contain the version number of the document currently stored in Elasticsearch (if found). =head3 C my $bulk = $es->bulk_helper( on_error => sub { my ($action,$response,$i) = @_; # do something }, ); The C callback is called for any error (unless the C) callback has already been called). =head2 Disabling callbacks and autoflush If you want to be in control of flushing, and you just want to receive the raw response that Elasticsearch sends instead of using callbacks, then you can do so as follows: my $bulk = $es->bulk_helper( max_count => 0, max_size => 0, on_error => undef ); $bulk->add_actions(....); $response = $bulk->flush; =head1 CREATE, INDEX, UPDATE, DELETE =head2 C $bulk->add_action( create => { ...params... }, index => { ...params... }, update => { ...params... }, delete => { ...params... } ); The C method allows you to add multiple C, C, C and C actions to the queue. The first value is the action type, and the second value is the parameters that describe that action. See the individual helper methods below for details. B Parameters like C or C can be specified as C or as C<_index>, so the following two lines are equivalent: index => { index => 'index', type => 'type', id => 1, source => {...}}, index => { _index => 'index', _type => 'type', _id => 1, source => {...}}, B The C and C parameters can be specified in the params for any action, but if not specified, will default to the C and C values specified in L. These are required parameters: they must be specified either in L or in every action. =head2 C $bulk->create( { index => 'custom_index', source => { doc body }}, { type => 'custom_type', id => 1, source => { doc body }}, ... ); The C helper method allows you to add multiple C actions. It accepts the same parameters as L except that the document body should be passed as the C or C<_source> parameter, instead of as C. =head2 C $bulk->create_docs( { doc body }, { doc body }, ... ); The C helper is a shorter form of L which can be used when you are using the default C and C as set in L and you are not specifying a custom C per document. In this case, you can just pass the individual document bodies. =head2 C $bulk->index( { index => 'custom_index', source => { doc body }}, { type => 'custom_type', id => 1, source => { doc body }}, ... ); The C helper method allows you to add multiple C actions. It accepts the same parameters as L except that the document body should be passed as the C or C<_source> parameter, instead of as C. =head2 C $bulk->delete( { index => 'custom_index', id => 1}, { type => 'custom_type', id => 2}, ... ); The C helper method allows you to add multiple C actions. It accepts the same parameters as L. =head2 C $bulk->delete_ids(1,2,3...) The C helper method can be used when all of the documents you want to delete have the default C and C as set in L. In this case, all you have to do is to pass in a list of IDs. =head2 C $bulk->update( { id => 1, doc => { partial doc }, doc_as_upsert => 1 }, { id => 2, script => { script } upsert => { upsert doc } }, ... ); The C helper method allows you to add multiple C actions. It accepts the same parameters as L. An update can either use a I which gets merged with an existing doc (example 1 above), or can use a C