mirror of
https://github.com/simon987/music-graph-api.git
synced 2025-04-19 09:56:43 +00:00
Add artist details, members endpoints
This commit is contained in:
parent
99cd73db07
commit
6a59ffdeef
@ -11,6 +11,6 @@ public class ArtistDetails {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String name;
|
public String name;
|
||||||
public List<String> releases;
|
public List<Release> releases;
|
||||||
public List<Tag> tags;
|
public List<Tag> tags;
|
||||||
}
|
}
|
||||||
|
14
src/main/java/net/simon987/musicgraph/entities/Release.java
Normal file
14
src/main/java/net/simon987/musicgraph/entities/Release.java
Normal file
@ -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 org.neo4j.driver.v1.types.Relationship;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
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.logging.Logger;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -37,11 +39,37 @@ public class MusicDatabase extends AbstractBinder {
|
|||||||
long end = System.nanoTime();
|
long end = System.nanoTime();
|
||||||
long took = (end - start) / 1000000;
|
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;
|
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) {
|
public ArtistDetails getArtistDetails(String mbid) {
|
||||||
|
|
||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
@ -51,7 +79,7 @@ public class MusicDatabase extends AbstractBinder {
|
|||||||
|
|
||||||
StatementResult result = query(session,
|
StatementResult result = query(session,
|
||||||
"MATCH (a:Artist {id: $mbid})-[:CREDITED_FOR]->(r:Release)\n" +
|
"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" +
|
"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" +
|
"RETURN a {name:a.name, releases:releases, tags:collect({weight: r.weight, name: t.name})}\n" +
|
||||||
"LIMIT 1",
|
"LIMIT 1",
|
||||||
@ -65,7 +93,16 @@ public class MusicDatabase extends AbstractBinder {
|
|||||||
Map<String, Object> map = result.next().get("a").asMap();
|
Map<String, Object> map = result.next().get("a").asMap();
|
||||||
|
|
||||||
details.name = (String) map.get("name");
|
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(
|
details.tags.addAll(
|
||||||
((List<Map>) map.get("tags"))
|
((List<Map>) map.get("tags"))
|
||||||
.stream()
|
.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()) {
|
try (Session session = driver.session()) {
|
||||||
|
|
||||||
@ -104,28 +141,7 @@ public class MusicDatabase extends AbstractBinder {
|
|||||||
|
|
||||||
SearchResult out = new SearchResult();
|
SearchResult out = new SearchResult();
|
||||||
|
|
||||||
long start = System.nanoTime();
|
parseRelatedResult(result, out);
|
||||||
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));
|
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
} catch (Exception e) {
|
} 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) {
|
private static Artist makeArtist(Node node) {
|
||||||
Artist artist = new Artist();
|
Artist artist = new Artist();
|
||||||
artist.id = node.id();
|
artist.id = node.id();
|
||||||
artist.mbid = node.get("id").asString();
|
artist.mbid = node.get("id").asString();
|
||||||
artist.name = node.get("name").asString();
|
artist.name = node.get("name").asString();
|
||||||
artist.labels = ImmutableList.copyOf(node.labels());
|
artist.labels = ImmutableList.copyOf(node.labels());
|
||||||
artist.listeners = node.get("listeners").asInt();
|
if (node.containsKey("listeners")) {
|
||||||
artist.playCount = node.get("playcount").asInt();
|
artist.listeners = node.get("listeners").asInt();
|
||||||
|
artist.playCount = node.get("playcount").asInt();
|
||||||
|
}
|
||||||
return artist;
|
return artist;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +221,9 @@ public class MusicDatabase extends AbstractBinder {
|
|||||||
|
|
||||||
relation.source = rel.startNodeId();
|
relation.source = rel.startNodeId();
|
||||||
relation.target = rel.endNodeId();
|
relation.target = rel.endNodeId();
|
||||||
relation.weight = rel.get("weight").asFloat();
|
if (rel.containsKey("weight")) {
|
||||||
|
relation.weight = rel.get("weight").asFloat();
|
||||||
|
}
|
||||||
|
|
||||||
return relation;
|
return relation;
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,26 @@ public class ArtistController {
|
|||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public SearchResult getRelated(@PathParam("mbid") String mbid) {
|
public SearchResult getRelated(@PathParam("mbid") String mbid) {
|
||||||
|
|
||||||
logger.info(String.format("Searching for %s", mbid));
|
logger.info(String.format("Related for %s", mbid));
|
||||||
return db.getRelated(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
|
@GET
|
||||||
|
Loading…
x
Reference in New Issue
Block a user