Querying MusicBrainz search API via PHP script - php

I'm trying to retrieve release info from the MusicBrainz database using a PHP script on my server. I have a list of songs, with song title and artist name, and I'm trying to retrieve the date of the first release of that song, along with other info about that release.
I realise that the search won't always be 100% accurate, but the list consists of fairly rare and unique songs so it should at least get me on a good track.
I've gotten pretty far with my script, it returns results and everything, but I'm unsure about how to write the query exactly. The documentation is quite confusing and doesn't feature an example where you search for both song title and artist.
This is my code:
// this info is normally fetched from my DB, but just as a simple example (as it is returned):
$artist = "ZZTop";
$song_title = "It's only Love";
// I'm having trouble with this part:
$mb_query = 'http://www.musicbrainz.org/ws/2/recording?query=' . $song_title .' ANDartist:' . $artist ;
$xml = simplexml_load_file($mb_query);
$releasedate = $xml->{'recording-list'}->recording[0]->{'release-list'}->release[0]->date;
At first I've tried to rawurlencode() the $artist and $song_title, but funnily enough, that didn't return any results, so I figured I'd just leave it as a plain string. The query returns results, but they are really off and I have the feeling only part of the query is getting picked up (for instance only the song title and not the artist).
Does anyone know the right way to do this?

The query created by your example code is this:
http://musicbrainz.org/ws/2/recording?query=It%27s%20only%20Love%20ANDartist:ZZTop
The problems are:
ANDartist: should be AND artist:
ZZTop should be "ZZ Top", otherwise the artist isn't found. You can add an alias `ZZTop if you really think that is how many people spell it
You might want to use phrases ("...") to search for full titles. Otherwise MB searches for titles including (It's or only or Love) and `artist:"ZZ TOP". However, results containing all words will be rated higher and show up on the top. So this is optional.
So the correct/precise query to use would be:
http://musicbrainz.org/ws/2/recording?query=%22It%27s%20only%20Love%22%20AND%20artist:%22ZZ%20Top%22 (2 results)
A more fuzzy query that works would be:
http://musicbrainz.org/ws/2/recording?query=It%27s%20only%20Love%20AND%20artist:%28ZZ%20Top%29 (80 results, using artist:(ZZ Top) to search for ZZ or Top artists)
See the MusicBrainz Search Documentation and Lucene Search Syntax for Details.
This code works for me (on PHP 5.5.13) instead of your line:
$mb_query = 'http://www.musicbrainz.org/ws/2/recording?query="'.$song_title.'"'
.' AND artist:"'.$artist.'"';
The PHP Documentation say you only need to use rawurlencode() prior to PHP 5.1.0.
Additionally you might want to use a pre-made library to work with the MusicBrainz Web Service more easily. There is a PHP Library for WS/2 listed on the MB Documentation. I haven't tried it myself though.
bonus:
If you have problems finding recordings because the artist is spelled differently on your end you can search for the artist (including aliases) first and then use the id of the artist for the recording search. Note that you can't use the alias in a recording search directly.
This query will search for ZZTop in the artist names, artist aliases and artist sortname:
http://musicbrainz.org/ws/2/artist?query=%22ZZTop%22
(see the artist search field documentation).
With that search you get an unique ID: a81259a0-a2f5-464b-866e-71220f2739f1. Note that you might get multiple results, so you might want to save a list with results with a high score and try other entries when you can't find the recording in the next step.
Now you can use the ID instead of the name in the recording search:
http://musicbrainz.org/ws/2/recording?query=%22I%27ts%20only%20Love%22%20AND%20arid:a81259a0-a2f5-464b-866e-71220f2739f1
You can also use arid:(... OR ...) when you got multiple results for the query for the artist.

Related

PHP/SQL Check if a similar entry already exists in the database

I have a search on my website and im trying to show a list of the most popular search terms on my site it sort of works but it isn't matching the strings close enough.
This is what i'm currently using:
$sql = "SELECT * FROM db WHERE r_name LIKE '%".$searchname."%' OR r_number like '%".$searchname."%'
However if a user searches for say Game Name and another searches for Game Name (Reviews) it will add 2 entries into my database, Is there a way to do a similarity test before entering the entry ?
yes, there is a way but it requires you to fiddle with it a little. there is a search called
SOUNDEX, which will match things that are very close. It might not be a perfect solution to your question, but it is definitely something that might get you started in the right direction.
SELECT * FROM db WHERE SOUNDEX( db.r_name ) LIKE SOUNDEX( '{$searchname}' );
I believe that if you have an entry 'lowercasexd' , and do soundex like('what is lowercasexd?'), it will find the entry that's associated with 'lowercasexd'.
Be aware that this type of search take a little while to run compare to '=' searches on indexed databases(on my database it does about 5-6k entries per second) so it is NOT recommended for anything big. If you want a near-perfect solution, I suggest you read about google's search mechanism, and look up some search engine source code if your project is significant enough.

Combining joined tag search with other parameters in RT sphinx

We use sphinx with a RealTime (RT) index to search through our database. Right now it contains fields such as longitude, latitude, title, content and it´s all working fine. The problem is that we want to implement a relational Tag-table and we are not sure how to do it.
In our current configuration we take advantage of a lot of the preconfigured methods available in the sphinxApi (for php), such as:
$this->_sphinxClient->setMatchMode(SPH_MATCH_EXTENDED2);
$this->_sphinxClient->SetGeoAnchor('latitude', 'longitude', (float)$this->latitude, (float)$this->longitude);
$this->_sphinxClient->SetFilterRange('price', $this->_priceMin, $this->_priceMax);
// And getting the final result with the:
$result = $this->_sphinxClient->Query($this->searchString, 'rt');
What we like to do if possible is either use mva (multi value attribute) or search through the results a second time with a join statement and seeding out the results that contain none of the tags.
We can´t get any of these options to work at the moment, so if anyone has any idea I would love a little help here. Use another index with id/tagname combination or a string attribute in the current one? Implement the search in the same query as the first one or search through those results in a second query with the tagjoin?
If I have missed anything important here please let me know, and thank you in advance!
Attach the tags to the current index. If you just need to search them, insert the tags in a full-text field and a string attribute if you want to get the tags as well in result. If you need to do grouping, you can:
use a MVA, but you will need to make a map between tag name and a tag id
use a JSON attribute. You can use IN on an array of strings like for MVA. For something more advanced you can use ALL() or ANY() functions.
For grouping, remember to use SetArrayResult(true). Also I recommend switching to SphinxQL interface.

Matching a user entered title to a category - large INNODB database

I have a large INNODB database with over 2 million products on it. The 'products' table has the following fields: id,title,description,category.
There is also a MyISAM table called 'category' that contains a list of all categories used on the website. This has the following fields: id,name,keywords,parentid.
My question is more about the logic rather than code, but what I am trying to achieve is as follows:
When a user lists a new product on the site, as they are typing the description it should try to work out what category to put the product in (with good accuracy).
I tried this initially by using MySQL MATCH() to match the entered title against a list of keywords in the category table, but this was far from accurate.
A better idea seems to be to match the user entered title against titles for products already in the database, grouping them by the category they are in and then sorting them by the largest group. However, on an INNODB database I obviously can't use fulltext, and with 2mill items I think it would be pretty slow anyway?
How would you do it - I guess it would need to be a similar way to how stackoverflow displays similar questions?
A fulltext index on 2 million records is a valid option, if you are running on a decent server. The inital indexing will take a while, that's for sure, but searches should be reasonably fast, MySQL can take it.
InnoDB supports fulltext indexes as of v5.6.4. You should consider upgrading.
If upgrading is not an option, please see this previous answer of mine where I suggest a workaround.
For your use case, you may want to take a look at the WITH QUERY EXPANSION option:
It works by performing the search twice, where the search phrase for the second search is the original search phrase concatenated with the few most highly relevant documents from the first search. Thus, if one of these documents contains the word “databases” and the word “MySQL”, the second search finds the documents that contain the word “MySQL” even if they do not contain the word “database”

PHP MySQL Search Suggestions

In my web application there will be several users. and they have their own contents uploaded to my webapp. For each content they upload it has a title, description and tags(keywords). I can write a search script to search for content or user name. but they keywords when they have given with a spelling mistake it doesn't return any result. For example if there is a user named "Michael" in the database and the search query was "Micheal" i should get "Did you mean to search for 'Michael'" which is none other than a search suggestion.
Also this suggestion should be for the contents uploaded by the user. An user may keep their content's title as "Michael's activities May 2011" and suggestions should be generated for individual words.
You could use SOUNDEX to search for similar-sounding names, like that:
SELECT * FROM users WHERE SOUNDEX(name) = SOUNDEX(:input)
or like that
SELECT * FROM users WHERE name SOUNDS_LIKE :input
(which is completely equivalent)
Edit: if you need to use an algorithm other than Soundex, as Martin Hohenberg suggested, you would need to add an extra column to your table, called, for example, sound_equivalent. (This is actually a more efficient solution as this column can be indexed). The request would then be:
SELECT * FROM users WHERE sound_equivalent = :input_sound_equivalent
The content of the sound_equivalent column can then be generated with a PHP algorithm, and inserted in the table with the rest of user parameters.
You can also use the php library pspell to get suggestions if you have no search results.
Maybe create a database of the most common words (like: dog, house, city, numbers, water, internet). Don't need to make it big (<10000 words).
Then when you explode the search term, check the "word" database for words LIKE the search terms. Then just echo out the suggestions.

Trending Search Help

My site acts like a search engine where people enter search queries on the main page. I wanted to make a trending / recent feature where each query gets recorded into a mysql database, then from that data, calculates which searches are being searched the most, and then displayed back on the page labeled as trending searches. Also, under that, I would like "recent searches" which simply displays the last 5 or so searches.
Honestly, I have no experience with mysql. I don't even know how to move data from my site to mysql. Any help would be appreciated. I searched and searched these questions and google, but didn't find anything. Thanks!
First of all, you need to CREATE a DATABASE, in which you want a table with a timestamp and the keyword that's been searched. (CREATE TABLE)
Then you want to store each keyword access into this table (INSERT INTO ... VALUES ...)
Then you can select the top key words by creating a SELECT query with a "GROUP BY keyword", ORDER ing by COUNT(*) (the number of occurrences of a keyword)
This is a bit vague, but you'll need to go through a number of steps so I've uppercased the terms you'd need to google for each step. Do come back if you run into complications in any of those steps!

Categories