Skip to content

Commit

Permalink
Port in the search_expanded logic from the frontend
Browse files Browse the repository at this point in the history
Also rename the web_like endpoint to simple. This needs reevaluation
later.
  • Loading branch information
jberger committed Nov 20, 2016
1 parent 14936ac commit 0209ae1
Show file tree
Hide file tree
Showing 2 changed files with 163 additions and 7 deletions.
15 changes: 13 additions & 2 deletions lib/MetaCPAN/Server/Controller/Search/WebLike.pm
Expand Up @@ -9,14 +9,25 @@ BEGIN { extends 'MetaCPAN::Server::Controller' }

with 'MetaCPAN::Server::Role::JSONP';

sub get : Chained('/search/index') : PathPart('web_like') : Args(0) {
sub simple : Chained('/search/index') : PathPart('simple') : Args(0) {
my ( $self, $c ) = @_;
my $args = $c->req->params;

my $model = $c->model('Search');
my $query = $model->build_query( $args->{q} );

$c->stash( $model->run_query($query) );
$c->stash( $model->run_query( file => $query ) );
}

sub expanded : Chained('/search/index') : PathPart('expanded') : Args(0) {
my ( $self, $c ) = @_;
my $args = $c->req->params;
my $query = $args->{q};

my $model = $c->model('Search');
my $results = $model->search_expanded($query);

$c->stash($results);
}

1;
155 changes: 150 additions & 5 deletions lib/MetaCPAN/Server/Model/Search.pm
Expand Up @@ -8,7 +8,8 @@ use Moose;
extends 'MetaCPAN::Server::Model::CPAN';

use Hash::Merge qw( merge );
use List::Util qw(uniq);
use List::Util qw( max sum uniq );
use MetaCPAN::Util qw( single_valued_arrayref_to_scalar );

my $RESULTS_PER_RUN = 200;
my @ROGUE_DISTRIBUTIONS
Expand All @@ -20,6 +21,47 @@ sub _not_rogue {
return { not => { filter => { or => \@rogue_dists } } };
}

sub search_expanded {
my ( $self, $query, $from, $page_size ) = @_;
$page_size //= 20;
$from //= 0;

# When used for a distribution or module search, the limit is included in
# thl query and ES does the right thing.
my $es_query = $self->build_query(
$query,
{
size => $page_size,
from => $from
}
);

#return $es_query;
my $data = $self->run_query( file => $es_query );

my @distributions = uniq
map {
single_valued_arrayref_to_scalar( $_->{fields} );
$_->{fields}->{distribution}
} @{ $data->{hits}->{hits} };

# Everything after this will fail (slowly and silently) without results.
return {} unless @distributions;

my @ids = map { $_->{fields}->{id} } @{ $data->{hits}->{hits} };
my $descriptions = $self->search_descriptions(@ids);
my $favorites = $self->search_favorites(@distributions);
my $results = $self->_extract_results( $data, $favorites );
map { $_->{description} = $descriptions->{results}->{ $_->{id} } }
@{$results};
my $return = {
results => [ map { [$_] } @$results ],
total => $data->{hits}->{total},
took => sum( grep {defined} $data->{took}, $favorites->{took} )
};
return $return;
}

# was sub search {}
sub build_query {
my ( $self, $query, $params ) = @_;
Expand Down Expand Up @@ -71,9 +113,8 @@ sub build_query {
},
{
query_string => {
fields => [
qw(abstract.analyzed pod.analyzed)
],
fields =>
[qw(abstract.analyzed pod.analyzed)],
query => $clean,
default_operator => 'AND',
allow_leading_wildcard => 0,
Expand Down Expand Up @@ -174,12 +215,116 @@ sub build_query {
}

sub run_query {
my ( $self, $query ) = @_;
my ( $self, $type, $query ) = @_;
return $self->es->search(
index => $self->index,
type => $type,
body => $query,
);
}

sub _build_search_descriptions_query {
my ( $self, @ids ) = @_;
my $query = {
query => {
filtered => {
query => { match_all => {} },
filter => {
or => [ map { { term => { id => $_ } } } @ids ]
}
}
},
fields => [qw(description id)],
size => scalar @ids,
};
return $query;
}

sub search_descriptions {
my ( $self, @ids ) = @_;
return {} unless @ids;

my $query = $self->_build_search_descriptions_query(@ids);
my $data = $self->run_query( file => $query );
my $results = {
results => {
map { $_->{id} => $_->{description} }
map { single_valued_arrayref_to_scalar( $_->{fields} ) }
@{ $data->{hits}->{hits} }
},
took => $data->{took}
};
return $results;
}

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

my $query = {
size => 0,
query => {
filtered => {
query => { match_all => {} },
filter => {
or => [
map { { term => { 'distribution' => $_ } } }
@distributions
]
}
}
},
aggregations => {
favorites => {
terms => {
field => 'distribution',
size => scalar @distributions,
},
},
}
};

return $query;
}

sub search_favorites {
my ( $self, @distributions ) = @_;
@distributions = uniq @distributions;

# If there are no distributions this will build a query with an empty
# filter and ES will return a parser error... so just skip it.
return {} unless @distributions;

my $query = $self->_build_search_favorites_query(@distributions);
my $data = $self->run_query( favorite => $query );

my $results = {
took => $data->{took},
favorites => {
map { $_->{key} => $_->{doc_count} }
@{ $data->{aggregations}->{favorites}->{buckets} }
},
};
return $results;
}

sub _extract_results {
my ( $self, $results, $favorites ) = @_;
return [
map {
my $res = $_;
single_valued_arrayref_to_scalar( $res->{fields} );
my $dist = $res->{fields}{distribution};
+{
%{ $res->{fields} },
%{ $res->{_source} },
abstract => $res->{fields}{'abstract.analyzed'},
score => $res->{_score},
favorites => $favorites->{favorites}{$dist},
myfavorite => $favorites->{myfavorites}{$dist},
}
} @{ $results->{hits}{hits} }
];
}

1;

0 comments on commit 0209ae1

Please sign in to comment.