1
0
mirror of https://github.com/simon987/music-graph-api.git synced 2025-04-18 01:16:42 +00:00

Add artist details, members endpoints

This commit is contained in:
simon 2019-05-21 12:38:19 -04:00
parent 99cd73db07
commit 6a59ffdeef
4 changed files with 138 additions and 33 deletions
src/main/java/net/simon987/musicgraph

@ -11,6 +11,6 @@ public class ArtistDetails {
}
public String name;
public List<String> releases;
public List<Release> releases;
public List<Tag> tags;
}

@ -0,0 +1,14 @@
package net.simon987.musicgraph.entities;
public class Release {
public String mbid;
public String name;
public long year;
public Release(String mbid, String name, long year) {
this.mbid = mbid;
this.name = name;
this.year = year;
}
}

@ -9,7 +9,9 @@ import org.neo4j.driver.v1.types.Node;
import org.neo4j.driver.v1.types.Relationship;
import javax.inject.Singleton;
import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import java.util.stream.Collectors;
@ -37,11 +39,37 @@ public class MusicDatabase extends AbstractBinder {
long end = System.nanoTime();
long took = (end - start) / 1000000;
logger.info(String.format("Query %s (Took %dms)", query, took));
logger.info(String.format("Query %s (Took %dms)", query.replace('\n', ' '), took));
return result;
}
public SearchResult getArtistMembers(String mbid) {
try (Session session = driver.session()) {
Map<String, Object> params = new HashMap<>();
params.put("mbid", mbid);
StatementResult result = query(session,
"MATCH (a:Artist)-[r]-(b)\n" +
"WHERE a.id = $mbid AND NOT type(r) = \"IS_RELATED_TO\"\n" +
"RETURN a as artist, a {rels: collect(DISTINCT r), nodes: collect(DISTINCT b)} as rank1\n" +
"LIMIT 1",
params);
SearchResult out = new SearchResult();
parseRelatedResult(result, out);
return out;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public ArtistDetails getArtistDetails(String mbid) {
Map<String, Object> params = new HashMap<>();
@ -51,7 +79,7 @@ public class MusicDatabase extends AbstractBinder {
StatementResult result = query(session,
"MATCH (a:Artist {id: $mbid})-[:CREDITED_FOR]->(r:Release)\n" +
"WITH collect(r.id) as releases, a\n" +
"WITH collect({id:r.id, name:r.name, year:r.year}) as releases, a\n" +
"OPTIONAL MATCH (a)-[r:IS_TAGGED]->(t:Tag)\n" +
"RETURN a {name:a.name, releases:releases, tags:collect({weight: r.weight, name: t.name})}\n" +
"LIMIT 1",
@ -65,7 +93,16 @@ public class MusicDatabase extends AbstractBinder {
Map<String, Object> map = result.next().get("a").asMap();
details.name = (String) map.get("name");
details.releases.addAll((Collection<String>) map.get("releases"));
details.releases.addAll(
((List<Map>) map.get("releases"))
.stream()
.map(x -> new Release(
(String) x.get("id"),
(String) x.get("name"),
(Long) x.get("year")
)).collect(Collectors.toList())
);
details.tags.addAll(
((List<Map>) map.get("tags"))
.stream()
@ -85,7 +122,7 @@ public class MusicDatabase extends AbstractBinder {
}
}
public SearchResult getRelated(String mbid) {
public SearchResult getRelatedById(String mbid) {
try (Session session = driver.session()) {
@ -104,28 +141,7 @@ public class MusicDatabase extends AbstractBinder {
SearchResult out = new SearchResult();
long start = System.nanoTime();
while (result.hasNext()) {
Record row = result.next();
out.artists.add(makeArtist(row.get(0).asNode()));
var rank1 = row.get(1).asMap();
out.relations.addAll(((List<Relationship>) rank1.get("rels"))
.stream()
.map(MusicDatabase::makeRelation)
.collect(Collectors.toList()
));
out.artists.addAll(((List<Node>) rank1.get("nodes"))
.stream()
.map(MusicDatabase::makeArtist)
.collect(Collectors.toList()
));
}
long end = System.nanoTime();
long took = (end - start) / 1000000;
logger.info(String.format("Fetched search result (Took %dms)", took));
parseRelatedResult(result, out);
return out;
} catch (Exception e) {
@ -134,14 +150,69 @@ public class MusicDatabase extends AbstractBinder {
}
}
public SearchResult getRelatedByName(String name) {
try (Session session = driver.session()) {
Map<String, Object> params = new HashMap<>();
params.put("name", name);
StatementResult result = query(session,
"MATCH (a:Artist)-[r:IS_RELATED_TO]-(b)\n" +
"WHERE a.name = $name\n" +
// Only match artists with > 0 releases
"MATCH (b)-[:CREDITED_FOR]->(:Release)\n" +
"WHERE r.weight > 0.25\n" +
"RETURN a as artist, a {rels: collect(DISTINCT r), nodes: collect(DISTINCT b)} as rank1\n" +
"LIMIT 1",
params);
SearchResult out = new SearchResult();
parseRelatedResult(result, out);
return out;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private void parseRelatedResult(StatementResult result, SearchResult out) {
long start = System.nanoTime();
while (result.hasNext()) {
Record row = result.next();
out.artists.add(makeArtist(row.get(0).asNode()));
var rank1 = row.get(1).asMap();
out.relations.addAll(((List<Relationship>) rank1.get("rels"))
.stream()
.map(MusicDatabase::makeRelation)
.collect(Collectors.toList()
));
out.artists.addAll(((List<Node>) rank1.get("nodes"))
.stream()
.map(MusicDatabase::makeArtist)
.collect(Collectors.toList()
));
}
long end = System.nanoTime();
long took = (end - start) / 1000000;
logger.info(String.format("Fetched search result (Took %dms)", took));
}
private static Artist makeArtist(Node node) {
Artist artist = new Artist();
artist.id = node.id();
artist.mbid = node.get("id").asString();
artist.name = node.get("name").asString();
artist.labels = ImmutableList.copyOf(node.labels());
artist.listeners = node.get("listeners").asInt();
artist.playCount = node.get("playcount").asInt();
if (node.containsKey("listeners")) {
artist.listeners = node.get("listeners").asInt();
artist.playCount = node.get("playcount").asInt();
}
return artist;
}
@ -150,7 +221,9 @@ public class MusicDatabase extends AbstractBinder {
relation.source = rel.startNodeId();
relation.target = rel.endNodeId();
relation.weight = rel.get("weight").asFloat();
if (rel.containsKey("weight")) {
relation.weight = rel.get("weight").asFloat();
}
return relation;
}

@ -26,8 +26,26 @@ public class ArtistController {
@Produces(MediaType.APPLICATION_JSON)
public SearchResult getRelated(@PathParam("mbid") String mbid) {
logger.info(String.format("Searching for %s", mbid));
return db.getRelated(mbid);
logger.info(String.format("Related for %s", mbid));
return db.getRelatedById(mbid);
}
@GET
@Path("members/{mbid}")
@Produces(MediaType.APPLICATION_JSON)
public SearchResult getMembers(@PathParam("mbid") String mbid) {
logger.info(String.format("Members for %s", mbid));
return db.getArtistMembers(mbid);
}
@GET
@Path("related_by_name/{name}")
@Produces(MediaType.APPLICATION_JSON)
public SearchResult getRelatedByName(@PathParam("name") String name) {
logger.info(String.format("Related for %s", name));
return db.getRelatedByName(name);
}
@GET