Skip to content

Commit a29eff9

Browse files
committed
always use suggester for autocomplete
We have two autocomplete end points. The old one is no longer used by the front end. The new one uses the suggest API. Rewrite both end points to use the suggest SPI, just returning data in different forms.
1 parent 374abed commit a29eff9

File tree

2 files changed

+114
-69
lines changed

2 files changed

+114
-69
lines changed

lib/MetaCPAN/Document/File/Set.pm

+85-69
Original file line numberDiff line numberDiff line change
@@ -271,74 +271,33 @@ sub history {
271271
return $search->sort( [ { date => 'desc' } ] );
272272
}
273273

274-
sub autocomplete {
275-
my ( $self, @terms ) = @_;
276-
277-
my $query = {
278-
bool => {
279-
must => [
280-
{
281-
multi_match => {
282-
query => join( q{ }, @terms ),
283-
type => 'most_fields',
284-
fields => [ 'documentation', 'documentation.*' ],
285-
analyzer => 'camelcase',
286-
minimum_should_match => '80%'
287-
}
288-
},
289-
{ exists => { field => 'documentation' } },
290-
{ term => { status => 'latest' } },
291-
{ term => { indexed => true } },
292-
{ term => { authorized => true } }
293-
],
294-
must_not =>
295-
[ { terms => { distribution => \@ROGUE_DISTRIBUTIONS } }, ],
296-
},
297-
};
298-
299-
my $data = $self->es->search(
300-
search_type => 'dfs_query_then_fetch',
301-
es_doc_path('file'),
302-
body => {
303-
query => $query,
304-
sort => [ '_score', 'documentation' ],
305-
_source => [qw( documentation release author distribution )],
306-
},
307-
);
308-
309-
# this is backcompat. we don't use this end point.
310-
$_->{fields} = delete $_->{_source} for @{ $data->{hits}{hits} };
311-
312-
return $data;
313-
}
314-
315-
sub autocomplete_suggester {
274+
sub _autocomplete {
316275
my ( $self, $query ) = @_;
317-
return $self unless $query;
318276

319277
my $search_size = 100;
320278

321-
my $suggestions = $self->es->suggest( {
279+
my $sugg_res = $self->es->search(
322280
es_doc_path('file'),
323281
body => {
324-
documentation => {
325-
text => $query,
326-
completion => {
327-
field => "suggest",
328-
size => $search_size,
329-
}
282+
suggest => {
283+
documentation => {
284+
text => $query,
285+
completion => {
286+
field => "suggest",
287+
size => $search_size,
288+
},
289+
},
330290
}
331291
},
332-
} );
292+
);
333293

334294
my %docs;
335-
336-
for my $suggest ( @{ $suggestions->{documentation}[0]{options} } ) {
295+
for my $suggest ( @{ $sugg_res->{suggest}{documentation}[0]{options} } ) {
337296
$docs{ $suggest->{text} } = max grep {defined}
338297
( $docs{ $suggest->{text} }, $suggest->{score} );
339298
}
340299

341-
my $data = $self->es->search( {
300+
my $res = $self->es->search(
342301
es_doc_path('file'),
343302
body => {
344303
query => {
@@ -366,34 +325,91 @@ sub autocomplete_suggester {
366325
) ],
367326
size => $search_size,
368327
},
369-
} );
328+
);
329+
330+
my $hits = $res->{hits}{hits};
331+
332+
my $fav_res
333+
= $self->agg_by_distributions(
334+
[ map $_->{_source}{distribution}, @$hits ] );
335+
336+
my $favs = $fav_res->{favorites};
370337

371338
my %valid = map {
372-
my %record = %{ $_->{_source} };
373-
$record{name} = delete $record{documentation}; # rename
374-
( $record{name} => \%record );
375-
} @{ $data->{hits}{hits} };
339+
my $source = $_->{_source};
340+
(
341+
$source->{documentation} => {
342+
%$source, favorites => $favs->{ $source->{distribution} },
343+
}
344+
);
345+
} @{ $res->{hits}{hits} };
376346

377347
# remove any exact match, it will be added later
378348
my $exact = delete $valid{$query};
379349

380-
my $favorites
381-
= $self->agg_by_distributions(
382-
[ map { $_->{distribution} } values %valid ] )->{favorites};
383-
384350
no warnings 'uninitialized';
385351
my @sorted = map { $valid{$_} }
386352
sort {
387-
$valid{$a}->{deprecated} <=> $valid{$b}->{deprecated}
388-
|| $favorites->{ $valid{$b}->{distribution} }
389-
<=> $favorites->{ $valid{$a}->{distribution} }
390-
|| $docs{$b} <=> $docs{$a}
391-
|| length($a) <=> length($b)
353+
my $a_data = $valid{$a};
354+
my $b_data = $valid{$b};
355+
$a_data->{deprecated} <=> $b_data->{deprecated}
356+
|| $b_data->{favorites} <=> $a_data->{favorites}
357+
|| $docs{$b} <=> $docs{$a}
358+
|| length($a) <=> length($b)
392359
|| $a cmp $b
393360
}
394361
keys %valid;
395362

396-
return +{ suggestions => [ grep {defined} ( $exact, @sorted ) ] };
363+
return {
364+
took => $sugg_res->{took} + $res->{took} + $fav_res->{took},
365+
suggestions => \@sorted,
366+
};
367+
}
368+
369+
sub autocomplete {
370+
my ( $self, @terms ) = @_;
371+
my $data = $self->_autocomplete( join ' ', @terms );
372+
373+
return {
374+
took => $data->{took},
375+
hits => {
376+
hits => [
377+
map {
378+
my $source = $_;
379+
+{
380+
fields => {
381+
map +( $_ => $source->{$_} ), qw(
382+
documentation
383+
release
384+
author
385+
distribution
386+
),
387+
},
388+
};
389+
} @{ $data->{suggestions} }
390+
],
391+
},
392+
};
393+
}
394+
395+
sub autocomplete_suggester {
396+
my ( $self, @terms ) = @_;
397+
my $data = $self->_autocomplete( join ' ', @terms );
398+
399+
return {
400+
took => $data->{took},
401+
suggestions => [
402+
map +{
403+
author => $_->{author},
404+
date => $_->{date},
405+
deprecated => $_->{deprecated},
406+
distribution => $_->{distribution},
407+
name => $_->{documentation},
408+
release => $_->{release},
409+
},
410+
@{ $data->{suggestions} }
411+
],
412+
};
397413
}
398414

399415
sub find_changes_files {

t/server/controller/search/autocomplete.t

+29
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,33 @@ test_psgi app, sub {
3232
}
3333
};
3434

35+
test_psgi app, sub {
36+
my $cb = shift;
37+
38+
# test ES script using doc['blah'] value
39+
{
40+
ok(
41+
my $res
42+
= $cb->(
43+
GET '/search/autocomplete/suggest?q=Multiple::Modu' ),
44+
'GET'
45+
);
46+
my $json = decode_json_ok($res);
47+
48+
my $got = [ map $_->{name}, @{ $json->{suggestions} } ];
49+
50+
is_deeply $got, [ qw(
51+
Multiple::Modules
52+
Multiple::Modules::A
53+
Multiple::Modules::B
54+
Multiple::Modules::RDeps
55+
Multiple::Modules::Tester
56+
Multiple::Modules::RDeps::A
57+
Multiple::Modules::RDeps::Deprecated
58+
) ],
59+
'results are sorted lexically by module name + length'
60+
or diag( Test::More::explain($got) );
61+
}
62+
};
63+
3564
done_testing;

0 commit comments

Comments
 (0)