From c3a5f8282e89893fa6da51fdeff90e4fe796169b Mon Sep 17 00:00:00 2001 From: Size43 Date: Thu, 28 May 2015 14:19:07 +0200 Subject: Loader for unified inbox --- .../main/java/org/rssin/neurons/FeedSorter.java | 13 ++-- app/src/main/java/org/rssin/neurons/Feedback.java | 3 +- app/src/main/java/org/rssin/rss/FeedItem.java | 64 +++++++++++++++-- .../java/org/rssin/rssin/FeedLoaderAndSorter.java | 14 +++- .../java/org/rssin/rssin/UnifiedFilterLoader.java | 84 ++++++++++++++++++++++ 5 files changed, 161 insertions(+), 17 deletions(-) mode change 100644 => 100755 app/src/main/java/org/rssin/rss/FeedItem.java create mode 100755 app/src/main/java/org/rssin/rssin/UnifiedFilterLoader.java (limited to 'app/src/main/java') diff --git a/app/src/main/java/org/rssin/neurons/FeedSorter.java b/app/src/main/java/org/rssin/neurons/FeedSorter.java index 910057f..fe1e998 100755 --- a/app/src/main/java/org/rssin/neurons/FeedSorter.java +++ b/app/src/main/java/org/rssin/neurons/FeedSorter.java @@ -33,7 +33,7 @@ public class FeedSorter implements Storable { private void writeObject(java.io.ObjectOutputStream stream) throws IOException { stream.writeObject(nn); - stream.writeObject(trainingCases); + SerializationTools.writeList(trainingCases, stream); SerializationTools.writeArray(isNthMonthInput, stream); SerializationTools.writeArray(isNthWeekDayInput, stream); stream.writeInt(isMorning); @@ -48,7 +48,7 @@ public class FeedSorter implements Storable { private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { nn = (MultiNeuralNetwork) stream.readObject(); - trainingCases = (List) stream.readObject(); + trainingCases = SerializationTools.readList(stream); isNthMonthInput = SerializationTools.readArrayInt(stream); isNthWeekDayInput = SerializationTools.readArrayInt(stream); isMorning = stream.readInt(); @@ -183,22 +183,17 @@ public class FeedSorter implements Storable { */ public List sortItems(List items) { final int SECONDS_IN_DAY = 24 * 60 * 60; - final List newItems = new ArrayList<>(items); - final Hashtable predictions = new Hashtable<>(); for (FeedItem item : newItems) { PredictionInterface prediction = getPrediction(item); - predictions.put(item, (long) (prediction.getOutput() * SECONDS_IN_DAY)); + item.setScore((long) (item.getPubDate().getTime() / 1000 + prediction.getOutput() * SECONDS_IN_DAY)); } Collections.sort(newItems, new Comparator() { @Override public int compare(FeedItem lhs, FeedItem rhs) { - long lhsScore = lhs.getPubDate().getTime() / 1000 + predictions.get(lhs); - long rhsScore = rhs.getPubDate().getTime() / 1000 + predictions.get(rhs); - - return (int) Math.signum(rhsScore - lhsScore); + return (int) Math.signum(rhs.getScore() - lhs.getScore()); } }); diff --git a/app/src/main/java/org/rssin/neurons/Feedback.java b/app/src/main/java/org/rssin/neurons/Feedback.java index fe59b1b..59d3246 100755 --- a/app/src/main/java/org/rssin/neurons/Feedback.java +++ b/app/src/main/java/org/rssin/neurons/Feedback.java @@ -2,13 +2,14 @@ package org.rssin.neurons; /** * @author Jos. + * Feedback for the Neural Network. */ public enum Feedback { Like(1.0d), Dislike(-1.0d); private final double expectedOutput; - private Feedback(double expectedOutput) { + Feedback(double expectedOutput) { this.expectedOutput = expectedOutput; } diff --git a/app/src/main/java/org/rssin/rss/FeedItem.java b/app/src/main/java/org/rssin/rss/FeedItem.java old mode 100644 new mode 100755 index bb074cd..f7805d8 --- a/app/src/main/java/org/rssin/rss/FeedItem.java +++ b/app/src/main/java/org/rssin/rss/FeedItem.java @@ -15,11 +15,11 @@ public class FeedItem { private String description; private String link; private String author; - private List category = new LinkedList<>(); private String comments; private String enclosure; private String source; - private boolean isRead; + private List category = new LinkedList<>(); + private transient long score = -1; public FeedItem(String guid, Date pubDate, String title, String description, String link, String author, List category, String comments, String enclosure, String source) @@ -123,11 +123,63 @@ public class FeedItem { return title + "\n" + description + " - " + author; } - public boolean isRead() { - return isRead; + @Override + public int hashCode() { + int hash = 17; + + if(guid != null) + { + hash = hash * 23 + guid.hashCode(); + } + + if(link != null) + { + hash = hash * 23 + link.hashCode(); + } + + if(title != null) + { + hash = hash * 23 + title.hashCode(); + } + + if(pubDate != null) + { + hash = hash * 23 + pubDate.hashCode(); + } + + return hash; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof FeedItem)) + return false; + + if (obj == this) + return true; + + FeedItem other = (FeedItem) obj; + return (guid == null && other.guid == null) || (guid != null && guid.equals(other.guid)) + && (pubDate == null && other.pubDate == null) || (pubDate != null && pubDate.equals(other.pubDate)) + && (title == null && other.title == null) || (title != null && title.equals(other.title)) + && (description == null && other.description == null) || (description != null && description.equals(other.description)) + && (link == null && other.link == null) || (link != null && link.equals(other.link)) + && (author == null && other.author == null) || (author != null && author.equals(other.author)) + && (comments == null && other.comments == null) || (comments != null && comments.equals(other.comments)) + && (enclosure == null && other.enclosure == null) || (enclosure != null && enclosure.equals(other.enclosure)) + && (source == null && other.source == null) || (source != null && source.equals(other.source)); + } + + public long getScore() { + if(score == -1) + { + throw new UnsupportedOperationException("score not set"); + } + + return score; } - public void setIsRead(boolean isRead) { - this.isRead = isRead; + public void setScore(long score) { + this.score = score; } } diff --git a/app/src/main/java/org/rssin/rssin/FeedLoaderAndSorter.java b/app/src/main/java/org/rssin/rssin/FeedLoaderAndSorter.java index 2ec3cfd..e1fbbab 100755 --- a/app/src/main/java/org/rssin/rssin/FeedLoaderAndSorter.java +++ b/app/src/main/java/org/rssin/rssin/FeedLoaderAndSorter.java @@ -85,10 +85,22 @@ public class FeedLoaderAndSorter { { for(Keyword keyword : filter.getKeywords()) { - if(contains(item.getTitle(), keyword.getKeyword())) + String word = keyword.getKeyword(); + if(contains(item.getTitle(), word) + || contains(item.getAuthor(), word)) { return true; } + + + + for(String category : item.getCategory()) + { + if(contains(category, word)) + { + return true; + } + } } return filter.getKeywords().size() == 0; diff --git a/app/src/main/java/org/rssin/rssin/UnifiedFilterLoader.java b/app/src/main/java/org/rssin/rssin/UnifiedFilterLoader.java new file mode 100755 index 0000000..9740380 --- /dev/null +++ b/app/src/main/java/org/rssin/rssin/UnifiedFilterLoader.java @@ -0,0 +1,84 @@ +package org.rssin.rssin; + +import org.rssin.http.Fetcher; +import org.rssin.listener.Listener; +import org.rssin.listener.RealtimeListener; +import org.rssin.rss.FeedItem; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; + +/** + * @author Jos. + * This class merges the FeedItems from multiple Filters together into one list of FeedItems. + */ +public class UnifiedFilterLoader { + + private List filters; + public UnifiedFilterLoader(List filters) + { + this.filters = filters; + } + + /** + * Loads the feed(s), filters it, sorts it, and returns the result. + * @param fetcher HTTP Fetcher + * @param listener Listener for when the fetcher finishes + */ + public void getFilteredFeedItems(Fetcher fetcher, final Listener> listener) { + // HashSet to make sure that there are no duplicates when merging multiple filters, since different filters + // may contain the same feed. + final HashSet resultingItems = new HashSet<>(); + final Counter counter = new Counter(filters.size()); + + for (Filter filter : filters) { + // Load the sorted FeedItems from the filters, and combine them. + FeedLoaderAndSorter loaderAndSorter = new FeedLoaderAndSorter(filter); + loaderAndSorter.getFilteredFeedItems(fetcher, new Listener>() { + @Override + public void onReceive(List data) { + resultingItems.addAll(data); + + if (counter.decr().isZero() || listener.getClass() == RealtimeListener.class) { + ArrayList newItems = new ArrayList(resultingItems); + + // Do another sort to make sure the items are still in the correct order. + // this uses the score set by the FeedSorter class, which is called + // in the Filter class. The Unified inbox does not have a separate network. + Collections.sort(newItems, new Comparator() { + @Override + public int compare(FeedItem lhs, FeedItem rhs) { + return (int) Math.signum(rhs.getScore() - lhs.getScore()); + } + }); + + listener.onReceive(newItems); + if (counter.decr().isZero() && listener.getClass() == RealtimeListener.class) { + ((RealtimeListener) listener).finish(); + } + } + } + }); + } + } + + private static class Counter { + int count; + + Counter (int initial) { + count = initial; + } + + public Counter decr() { + count--; + return this; + } + + public boolean isZero() { + return count == 0; + } + } +} -- cgit v1.2.3