oknozor / musicbrainz_rs

A wrapper around the musicbrainz API
MIT License
41 stars 18 forks source link

Add search queries #23

Open oknozor opened 5 years ago

oknozor commented 3 years ago

see : https://musicbrainz.org/doc/MusicBrainz_API/Search

ritiek commented 3 years ago

I've been fiddling with search queries, and trying to figure out how search queries on other entities maybe implemented. I tried to implement searches based on the Release type, but it seems like the API response further contains a release-group key for every release item: https://musicbrainz.org/ws/2/release/?query=release:Tonight,%20Tomorrow

This release-group contains only two further subkeys, which are title and primary-type. So, the library is unable to parse this as a valid ReleaseGroup struct, since our struct expects more than these 2 keys (which additionally includes the value for first-release-date). How would we implement this? Should we change all of the missing attributes to Option<T>? Or do we have a another approach in mind?

oknozor commented 3 years ago

I think adding more optional will be confusing for the end user. It would be simpler to use an associated type to the Search trait like so :

pub trait Search<'a> {
    type SearchResult;

    fn search(query: String) -> SearchQuery<Self::SearchResult>
   // ....

This way we could define a custom struct to hold the search result or reuse an existing one when possible.

Boscop commented 3 years ago

Which entity should I query if I want to auto-tag midi files based on artist and song title extracted from a midi filename? Should I query recordings, releases or works?

(Actually, the extraction is not trivial because the artist and song name can be in any order, with spelling mistakes, sometimes separated by -, sometimes by _, sometimes not separated, or with other punctuation in between, and sometimes the file name is only the artist or song name, sometimes even as one long word without spaces. So I need to do multiple queries to first determine which part is the artist and which is the song name. But maybe the API can meet me halfway with a certain endpoint that determines the artist and song name from a given filename string?)

oknozor commented 3 years ago

This could be complex depending on how much you know about what is in your midi filename. Currently search is only implemented for artist, but as soon as other entity are implemented (very soon) you will be able to try this out.

Let say you are trying to auto-tag "IAM - Demain c'est loin.midi"

I would probably start with something like this :

curl --request GET \
  --url 'https://musicbrainz.org/ws/2/recording/?query=title%3Ademain%20c'\''est%20loin%20AND%20artist%3Aiam%20OR%20artist%3ADemain%20c'\''est%20loin%20AND%20title%3Aiam%22&fmt=json'

This would translate into musicbrainz_rs (not implemented yet for recording) :

    let query = Recording::query_builder()
        .artist("Iam")
        .and()
        .title("Demain c'est loin")
        .or()
        .title(Iam")
        .and()
        .artist("Demain c'est loin")
        .build();

    let result = Artist::search(query).execute();

Also we currently don't expose the search score but this could be be useful for use cases like yours.

@ritiek do you think we could expose search score ?

ritiek commented 3 years ago

@Boscop I think fuzzy search capabilities could be somewhat useful too if you suspect spelling mistakes in filenames.

@ritiek do you think we could expose search score ?

The API search response does expose a ns2:score parameter. I think it would definitely be a good idea to support this in musicbrainz_rs.

Boscop commented 3 years ago

@ritiek Does musicbrainz support fuzzy search, too? (Many file names have spelling mistakes.)

ritiek commented 3 years ago

Yep, musicbrainz API does support it. Although I'm not sure how effective it would be for your use-case but it might be worth a try.

Boscop commented 3 years ago

Does this crate pass it through? So could I use it for any entity lookup with this crate?

ritiek commented 3 years ago

Yes, this crate will pass the fuzzy operator ~ to the musicbrainz API. But as @oknozor mentioned only artist search is implemented at the moment. So, something like this would work for fuzzy artist searches:

use musicbrainz_rs::entity::artist::Artist;
use musicbrainz_rs::prelude::*;

fn main() {
    let query = String::from("query=artist:kayden~");
    let query_result = Artist::search(query).execute().unwrap();
    println!("{:?}", query_result);
}

@oknozor I'm also curious on whether name is an actual searchable artist field? because I don't see it mentioned under artist search fields and it seems fuzzy searching an artist through name field doesn't return any results: query=name:kayden~

While it works as expected when using the artist field: query=artist:kayden~, but I'm not sure how to use Artist::query_builder() to build the query in this case if it's currently possible (I wrote the query directly in the above code).

oknozor commented 3 years ago

I'm also curious on whether name is an actual searchable artist field? because I don't see it mentioned under artist search fields and it seems fuzzy searching an artist through name field doesn't return any results: query=name:kayden~

I just checked you are correct. It was working previously with "name" because lucene seems to search on any field when the input field is unknown, unless you use fuzzy search.

We can fix this by adding #[query_builder_rename = "artist"] on Artist.name (see: https://github.com/oknozor/lucene_query_builder_rs#rename-fields).