Catmandu-Solr

 view release on metacpan or  search on metacpan

lib/Catmandu/Store/Solr.pm  view on Meta::CPAN


our $VERSION = '0.0304';

=head1 SYNOPSIS

    # From the command line

    # Import data into Solr
    $ catmandu import JSON to Solr  < data.json

    # Export data from ElasticSearch
    $ catmandu export Solr to JSON > data.json

    # Export only one record
    $ catmandu export Solr --id 1234

    # Export using an Solr query
    $ catmandu export Solr --query "name:Recruitment OR name:college"

    # Export using a CQL query (needs a CQL mapping)
    $ catmandu export Solr --q "name any college"

    # From Perl
    use Catmandu::Store::Solr;

    my $store = Catmandu::Store::Solr->new(url => 'http://localhost:8983/solr' );

    my $obj1 = $store->bag->add({ name => 'Patrick' });

    printf "obj1 stored as %s\n" , $obj1->{_id};

    # Force an id in the store
    my $obj2 = $store->bag->add({ _id => 'test123' , name => 'Nicolas' });

    # send all changes to solr (committed automatically)
    $store->bag->commit;

    #transaction: rollback issued after 'die'
    $store->transaction(sub{
        $bag->delete_all();
        die("oops, didn't want to do that!");
    });

    my $obj3 = $store->bag->get('test123');

    $store->bag->delete('test123');

    $store->bag->delete_all;

    # All bags are iterators
    $store->bag->each(sub { ... });
    $store->bag->take(10)->each(sub { ... });

    # Search
    # Any extra arguments will be passed on as is to Solr
    my $hits = $store->bag->search(query => 'name:Patrick');

=cut

has url        => (is => 'ro', default => sub {'http://localhost:8983/solr'});
has keep_alive => (is => 'ro', default => sub {0});
has solr    => (is => 'lazy');
has bag_key => (is => 'lazy', alias => 'bag_field');
has on_error => (
    is  => 'ro',
    isa => sub {
        array_includes([qw(throw ignore)], $_[0])
            or die("on_error must be 'throw' or 'ignore'");
    },
    lazy    => 1,
    default => sub {"throw"}
);
has _bags_used => (is => 'ro', lazy => 1, default => sub {[];});

around 'bag' => sub {
    my $orig = shift;
    my $self = shift;

    my $bags_used = $self->_bags_used;
    unless (array_includes($bags_used, $_[0])) {
        push @$bags_used, $_[0];
    }

    $orig->($self, @_);
};

sub _build_solr {
    my ($self) = @_;
    WebService::Solr->new(
        $_[0]->url,
        {
            autocommit     => 0,
            default_params => {wt => 'json'},
            agent => LWP::UserAgent->new(keep_alive => $self->keep_alive),
        }
    );
}

sub _build_bag_key {
    $_[0]->key_for('bag');
}

sub transaction {
    my ($self, $sub) = @_;

    if ($self->{_tx}) {
        return $sub->();
    }
    my $solr = $self->solr;
    my @res;

    eval {
#flush buffers of all known bags ( with commit=true ), to ensure correct state
        for my $bag_name (@{$self->_bags_used}) {
            $self->bag($bag_name)->commit;
        }

#mark store as 'in transaction'. All subsequent calls to commit only flushes buffers without setting 'commit' to 'true' in solr
        $self->{_tx} = 1;

        #transaction
        @res = $sub->();

        #flushing buffers of all known bags (with commit=false)
        for my $bag_name (@{$self->_bags_used}) {
            $self->bag($bag_name)->commit;
        }

        #commit in solr
        $solr->commit;

        #remove mark 'in transaction'
        $self->{_tx} = 0;
        1;
    } or do {
        my $err = $@;

#remove remaining documents from all buffers, because they were added during the transaction
        for my $bag_name (@{$self->_bags_used}) {
            $self->bag($bag_name)->clear_buffer;
        }

        #rollback in solr
        eval {$solr->rollback};

        #remove mark 'in transaction'
        $self->{_tx} = 0;
        Catmandu::Error->throw($err);
    };

    @res;
}

=head1 SOLR SCHEMA



( run in 2.511 seconds using v1.01-cache-2.11-cpan-5b529ec07f3 )