api/v0: implement similarity search for media
Use a very naive approach: define similarity as the number of shared tags between two media pieces. It can be implemented in SQL and produces decent results.
This commit is contained in:
parent
29aa172391
commit
c625ee860a
2 changed files with 52 additions and 0 deletions
|
@ -69,6 +69,8 @@ sub startup ($self)
|
|||
|
||||
$r->get("/media")->to("media#list")->name("list_media");
|
||||
$r->get("/media/<media_id:num>")->to("media#show")->name("show_media");
|
||||
$r->get("/media/similar/<media_id:num>")->to("media#similar")
|
||||
->name("search_similar_media");
|
||||
|
||||
$r->get("/tag")->to("tags#show")->name("show_tag");
|
||||
$r->get("/tags")->to("tags#list")->name("list_tags");
|
||||
|
|
|
@ -119,4 +119,54 @@ sub show ($self)
|
|||
});
|
||||
}
|
||||
|
||||
# Executes
|
||||
# SELECT *, COUNT(tag_id) AS similarity_score FROM tagged_media_view
|
||||
# WHERE tag_id IN (
|
||||
# SELECT tag_id FROM tagged_media_view WHERE media_id = m
|
||||
# ) AND media_id != m
|
||||
# GROUP BY media_id ORDER BY similarity_score
|
||||
sub similar ($self)
|
||||
{
|
||||
my $media_id = $self->stash("media_id");
|
||||
my $media = $self->schema->resultset("Media")
|
||||
->single({id => $media_id});
|
||||
|
||||
return $self->render(
|
||||
json => {error => "Media not found"},
|
||||
status => 404,
|
||||
) if !defined($media);
|
||||
|
||||
my %attrs = (
|
||||
select => ["tag_id"],
|
||||
rows => 100,
|
||||
);
|
||||
my $tags = $self->schema->resultset("MediaTag")
|
||||
->search({media_id => $media_id}, \%attrs)->as_query;
|
||||
|
||||
my %search = (
|
||||
media_id => {"!=", $media_id},
|
||||
tag_id => {"-in", $tags},
|
||||
);
|
||||
%attrs = (
|
||||
"+select" => [{count => "tag_id", -as => "similarity_score"}],
|
||||
"+as" => ["similarity_score"],
|
||||
group_by => "media_id",
|
||||
order_by => {-desc => "similarity_score"},
|
||||
rows => 6,
|
||||
);
|
||||
my @media = map +{
|
||||
id => $_->media_id,
|
||||
storage_id => $_->media_storage_id,
|
||||
filename => $_->media_filename,
|
||||
content_type => $_->media_content_type,
|
||||
upload_datetime => $_->media_upload_datetime,
|
||||
similarity_score => $_->get_column("similarity_score"),
|
||||
}, $self->schema->resultset("TaggedMediaView")
|
||||
->search(\%search, \%attrs)->all;
|
||||
|
||||
return $self->render(json => {
|
||||
media => [@media],
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue