package esl.cuenet.algorithms.firstk.impl;
import com.hp.hpl.jena.ontology.Individual;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.vocabulary.RDF;
import esl.cuenet.algorithms.firstk.Vote;
import esl.cuenet.algorithms.firstk.structs.eventgraph.Entity;
import esl.cuenet.algorithms.firstk.structs.eventgraph.Event;
import esl.cuenet.algorithms.firstk.structs.eventgraph.EventGraph;
import esl.cuenet.model.Constants;
import esl.cuenet.query.IResultIterator;
import esl.cuenet.query.IResultSet;
import esl.cuenet.query.QueryEngine;
import esl.datastructures.Location;
import esl.system.ExperimentsLogger;
import org.apache.log4j.Logger;
import java.util.*;
public class HashIndexedEntityVoter {
private Logger logger = Logger.getLogger(HashIndexedEntityVoter.class);
private ExperimentsLogger el = ExperimentsLogger.getInstance();
private CandidateVotingTable<String> candidateTable = new CandidateVotingTable<String>("eventgraph");
private HashMap<String, CandidateVotingTable<String>> discoveredCandidatesTables = new
HashMap<String, CandidateVotingTable<String>>();
private List<String> projectVarURIs = new ArrayList<String>();
private QueryEngine queryEngine = null;
private Property nameProperty = null;
private Property emailProperty = null;
private Property livesAtProperty = null;
private Property worksAtProperty = null;
private Property occursAtProperty = null;
private List<EntityContext> verifiedEntities = null;
private boolean impulseMode = false;
public HashIndexedEntityVoter(QueryEngine engine, OntModel model) {
this.queryEngine = engine;
nameProperty = model.getProperty(Constants.CuenetNamespace + "name");
emailProperty = model.getProperty(Constants.CuenetNamespace + "email");
livesAtProperty = model.getProperty(Constants.CuenetNamespace + "lives-at");
worksAtProperty = model.getProperty(Constants.CuenetNamespace + "works-at");
occursAtProperty = model.getProperty(Constants.CuenetNamespace + "occurs-at");
projectVarURIs.add(Constants.CuenetNamespace + "person");
verifiedEntities = new ArrayList<EntityContext>();
}
public Vote[] vote(EventGraph graph, List<Entity> discoverableEntities) {
List<Entity> graphEntities = graph.getEntities();
logger.info("Entities found: " + graphEntities.size());
Vote[] votes =checkForFewGE(graph, discoverableEntities);
if (votes != null) return votes;
List<EntityContext> discoverableEntityContexts = new ArrayList<EntityContext>();
for (Entity entity: discoverableEntities) {
String name = getLiteralValue(entity.getIndividual(), nameProperty);
String email = getLiteralValue(entity.getIndividual(), emailProperty);
if (email == null) email = EntityVoter.getEmail(name);
EntityContext ecx = new EntityContext(entity, name, email);
discoverableEntityContexts.add(ecx);
}
for (EntityContext ecx: discoverableEntityContexts) {
if (discoveredCandidatesTables.get(ecx.name) == null)
discover(ecx);
}
updateScoresForEventAttendees(graphEntities);
return extractTopDCandidates();
}
public Vote[] impulse(EventGraph graph, Event photoCaptureEvent) {
impulseMode = true;
vote(graph, graph.getParticipants(photoCaptureEvent));
Statement oaStatement = photoCaptureEvent.getIndividual().getProperty(occursAtProperty);
String uri = oaStatement.getObject().asResource().getURI();
int ix = uri.indexOf('_');
if (ix == -1) return null;
Location pceLocation = Location.getFromCache(uri.substring(ix+1));
List<LocationContext> lcxCandidates = new ArrayList<LocationContext>();
for (String entityName: discoveredCandidatesTables.keySet()) {
CandidateVotingTable<String> candidateTable = discoveredCandidatesTables.get(entityName);
Iterator<String> iter = candidateTable.iterator();
while(iter.hasNext()) {
String name = iter.next();
Individual dctInd = candidateTable.getScore(name).individual;
Location dctIndLocation = getLocation(dctInd);
if (dctIndLocation == null) continue;
lcxCandidates.add(new LocationContext(dctInd,
getLiteralValue(dctInd, nameProperty), dctIndLocation));
}
}
orderByLocation(lcxCandidates, pceLocation);
impulseMode = false;
return new Vote[0];
}
private void orderByLocation(List<LocationContext> lcxCandidates, final Location l0) {
logger.info("Order by Location: " + lcxCandidates.size());
if (lcxCandidates.size() == 0) return;
PriorityQueue<LocationContext> pq = new PriorityQueue<LocationContext>(lcxCandidates.size(), new Comparator<LocationContext>() {
@Override
public int compare(LocationContext lcx1, LocationContext lcx2) {
double dist1 = lcx1.location.getEuclideanDistance(l0);
double dist2 = lcx2.location.getEuclideanDistance(l0);
return (int)(dist1-dist2);
}
});
int i = 1;
for (LocationContext lcx: lcxCandidates) pq.add(lcx);
for (LocationContext l : pq) {
logger.info(i + " " + l.name);
if (i<10) el.list(i + " " + l.name);
i++;
}
logger.info("Leaving OrderByLocation");
}
public Vote[] impulse(EventGraph graph, Event photoCaptureEvent, String[] annotations) {
impulseMode = true;
vote(graph, graph.getParticipants(photoCaptureEvent));
Statement oaStatement = photoCaptureEvent.getIndividual().getProperty(occursAtProperty);
String uri = oaStatement.getObject().asResource().getURI();
int ix = uri.indexOf('_');
if (ix == -1) return null;
Location pceLocation = Location.getFromCache(uri.substring(ix+1));
List<LocationContext> lcxCandidates = new ArrayList<LocationContext>();
for (String entityName: discoveredCandidatesTables.keySet()) {
CandidateVotingTable<String> candidateTable = discoveredCandidatesTables.get(entityName);
Iterator<String> iter = candidateTable.iterator();
while(iter.hasNext()) {
String name = iter.next();
Individual dctInd = candidateTable.getScore(name).individual;
Location dctIndLocation = getLocation(dctInd);
if (dctIndLocation == null) continue;
lcxCandidates.add(new LocationContext(dctInd,
getLiteralValue(dctInd, nameProperty), dctIndLocation));
}
}
orderByLocation(lcxCandidates, pceLocation, annotations);
impulseMode = false;
return new Vote[0];
}
private void orderByLocation(List<LocationContext> lcxCandidates, final Location l0, String[] annotations) {
logger.info("Order by Location: " + lcxCandidates.size());
if (lcxCandidates.size() == 0) return;
PriorityQueue<LocationContext> pq = new PriorityQueue<LocationContext>(lcxCandidates.size(), new Comparator<LocationContext>() {
@Override
public int compare(LocationContext lcx1, LocationContext lcx2) {
double dist1 = lcx1.location.getEuclideanDistance(l0);
double dist2 = lcx2.location.getEuclideanDistance(l0);
return (int)(dist1-dist2);
}
});
int i = 1;
for (LocationContext lcx: lcxCandidates) pq.add(lcx);
for (LocationContext l : pq) {
//if you want to log all entries.
//el.list("Rank " + i + " " + l.name);
for (String ann: annotations) {
if (ann.equals(l.name)) {
logger.info("Rank " + i + " " + l.name);
el.list("Rank " + i + " " + l.name);
}
}
i++;
}
logger.info("Leaving OrderByLocation");
}
private LocationContext find(String name, List<LocationContext> lcxCandidates) {
for (LocationContext lcx: lcxCandidates) {
if (lcx.name.equals(name)) return lcx;
}
return null;
}
private Location getLocation(Individual dctInd) {
Statement lst = dctInd.getProperty(livesAtProperty);
if (lst == null) lst = dctInd.getProperty(worksAtProperty);
if (lst == null) return null;
String uri = lst.getObject().asResource().getURI();
int ix = uri.indexOf('_');
if (ix == -1) return null;
return Location.getFromCache(uri.substring(ix+1));
}
private Vote[] checkForFewGE(EventGraph graph, List<Entity> discoverableEntities) {
if (impulseMode) return null;
List<Entity> allEntities = graph.getEntities();
if ( (allEntities.size() - discoverableEntities.size()) > 10) {
logger.info("Too many participants to verify on everyone");
return null;
}
//Vote[] votes = new Vote[allEntities.size() - discoverableEntities.size()];
ArrayList<Vote> aVotes = new ArrayList<Vote>();
for (Entity gEnt: allEntities) {
String name = getLiteralValue(gEnt.getIndividual(), nameProperty);
if (containedIn(name, discoverableEntities)) continue;
if (isVerified(name)) continue;
Vote v = new Vote();
v.entity = gEnt.getIndividual();
v.entityID = name;
v.score = 1;
aVotes.add(v);
}
Vote[] votes = new Vote[aVotes.size()];
aVotes.toArray(votes);
return votes;
}
private boolean containedIn(String pEntName, List<Entity> originalParticipants) {
for (Entity e: originalParticipants) {
String p = getLiteralValue(e.getIndividual(), nameProperty);
if (p.equals(pEntName)) return true;
}
return false;
}
public void addToVerifiedList(Entity verifiedEntity) {
EntityContext ecx = new EntityContext(verifiedEntity,
getLiteralValue(verifiedEntity.getIndividual(), nameProperty),
getLiteralValue(verifiedEntity.getIndividual(), emailProperty));
verifiedEntities.add(ecx);
}
private Vote[] extractTopDCandidates() {
Iterator<String> ctIter = candidateTable.iterator();
ArrayList<Vote> nonZeroVotes = new ArrayList<Vote>();
while(ctIter.hasNext()) {
String name = ctIter.next();
Score<String> score = candidateTable.getScore(name);
if (score.scores > 0) nonZeroVotes.add(
new Vote(getLiteralValue(score.individual, nameProperty),
score.scores, score.individual));
}
int dups = 0;
for (Vote v: nonZeroVotes) {
if (discoveredCandidatesTables.get(v.entityID) != null ||
isVerified(v.entityID)) dups++;
}
Vote[] votes = new Vote[nonZeroVotes.size() - dups];
int i = 0;
for (Vote v: nonZeroVotes)
if (discoveredCandidatesTables.get(v.entityID) == null && !isVerified(v.entityID))
votes[i++] = v;
nonZeroVotes.toArray(votes);
return votes;
}
private void updateScoresForEventAttendees(List<Entity> entities) {
String name;
String[] names = new String[entities.size()];
int i=0;
for (Entity entity: entities) {
name = getLiteralValue(entity.getIndividual(), nameProperty);
names[i] = name; i++;
if ( !candidateTable.contains(name) )
candidateTable.addToCandidateTable(name, entity.getIndividual());
updateScoresForEventAttendee(name);
}
Arrays.sort(names);
for (String s: names) logger.info("--------------------> " + s);
}
private void updateScoresForEventAttendee(String name) {
for (Map.Entry<String, CandidateVotingTable<String>> dctEntry:
discoveredCandidatesTables.entrySet()) {
Score<String> score = dctEntry.getValue().getScore(name);
if (score == null) continue;
candidateTable.updateScore(name, score.scores + 1);
}
}
private void discover(EntityContext ecx) {
CandidateVotingTable<String> votingTable = new CandidateVotingTable<String>(ecx.name);
for (IResultSet resultSet : query(ecx)) {
IResultIterator resultIterator = resultSet.iterator();
while(resultIterator.hasNext()) {
Map<String, List<Individual>> result = resultIterator.next(projectVarURIs);
List<Individual> relatedCandidates = result.get(Constants.CuenetNamespace + "person");
updateScores(votingTable, relatedCandidates);
}
}
discoveredCandidatesTables.put(ecx.name, votingTable);
}
private void updateScores(CandidateVotingTable<String> votingTable,
List<Individual> relatedCandidates) {
String name;
for (Individual candidate: relatedCandidates) {
name = getLiteralValue(candidate, nameProperty);
if ( !votingTable.contains(name) ) votingTable.addToCandidateTable(name, candidate);
else votingTable.updateScore(name, 1);
}
}
private String getLiteralValue(Individual individual, Property property) {
Statement statement = individual.getProperty(property);
if (statement == null) return "unknown@u.com";
if (!statement.getObject().isLiteral()) return "unknown@u.com";
return statement.getObject().asLiteral().getString();
}
private List<IResultSet> query(EntityContext ecx) {
String sparqlQuery = "SELECT ?x \n" +
" WHERE { \n" +
"?x <" + RDF.type + "> <" + Constants.CuenetNamespace + "person> .\n" +
"?y <" + RDF.type + "> <" + Constants.CuenetNamespace + "person> .\n" +
"?y <" + Constants.CuenetNamespace + "knows" + ">" + " ?x .\n";
if (ecx.email != null)
sparqlQuery += "?y <" + Constants.CuenetNamespace + "email> \"" + ecx.email + "\" .\n";
if (ecx.name != null)
sparqlQuery += "?y <" + Constants.CuenetNamespace + "name> \"" + ecx.name + "\" .\n";
sparqlQuery += "}";
logger.info("Executing Sparql Query: \n" + sparqlQuery);
return queryEngine.execute(sparqlQuery);
}
private boolean isVerified(String name) {
for (EntityContext ecx: verifiedEntities) if (ecx.name.equals(name)) return true;
return false;
}
private class EntityContext {
public EntityContext(Entity entity, String name, String email) {
this.email = email;
this.entity = entity;
this.name = name;
}
Entity entity;
String name;
String email;
}
private class LocationContext {
public LocationContext(Individual ind, String name, Location location) {
this.ind = ind;
this.name = name;
this.location = location;
}
Location location;
String name;
Individual ind;
}
}