summaryrefslogtreecommitdiff
path: root/core/src/main/java
diff options
context:
space:
mode:
authorByteHamster <info@bytehamster.com>2020-01-01 16:21:09 +0100
committerByteHamster <info@bytehamster.com>2020-01-01 16:21:28 +0100
commit41af487a5b2d38ebd16323c00568912bbd4839a4 (patch)
tree9c6b7d3a34ab6e8a1930e490ed2065d652b25ec3 /core/src/main/java
parent5fc6877a87ab1da71244336ffd388bf3f0928415 (diff)
downloadAntennaPod-41af487a5b2d38ebd16323c00568912bbd4839a4.zip
Increased search performance
Diffstat (limited to 'core/src/main/java')
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/SearchResult.java42
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java130
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java78
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java138
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/SearchLocation.java21
5 files changed, 103 insertions, 306 deletions
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/SearchResult.java b/core/src/main/java/de/danoeh/antennapod/core/feed/SearchResult.java
index ea8eb7871..062a6abac 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/SearchResult.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/SearchResult.java
@@ -1,34 +1,22 @@
package de.danoeh.antennapod.core.feed;
-public class SearchResult {
- private final FeedComponent component;
- /** Additional information (e.g. where it was found) */
- private String subtitle;
- /** Higher value means more importance */
- private final int value;
-
- public SearchResult(FeedComponent component, int value, String subtitle) {
- super();
- this.component = component;
- this.value = value;
- this.subtitle = subtitle;
- }
+import de.danoeh.antennapod.core.storage.SearchLocation;
- public FeedComponent getComponent() {
- return component;
- }
-
- public String getSubtitle() {
- return subtitle;
- }
+public class SearchResult {
+ private final FeedComponent component;
+ private SearchLocation location;
- public void setSubtitle(String subtitle) {
- this.subtitle = subtitle;
- }
+ public SearchResult(FeedComponent component, SearchLocation location) {
+ super();
+ this.component = component;
+ this.location = location;
+ }
- public int getValue() {
- return value;
- }
-
+ public FeedComponent getComponent() {
+ return component;
+ }
+ public SearchLocation getLocation() {
+ return location;
+ }
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
index c4a06efa2..65e6bbbca 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
@@ -543,140 +543,20 @@ public final class DBTasks {
}
/**
- * Searches the titles of FeedItems of a specific Feed for a given
- * string.
+ * Searches the FeedItems of a specific Feed for a given string.
*
* @param context Used for accessing the DB.
* @param feedID The id of the feed whose items should be searched.
* @param query The search string.
- * @return A FutureTask object that executes the search request and returns the search result as a List of FeedItems.
+ * @return A FutureTask object that executes the search request
+ * and returns the search result as a List of FeedItems.
*/
- public static FutureTask<List<FeedItem>> searchFeedItemTitle(final Context context,
+ public static FutureTask<List<FeedItem>> searchFeedItems(final Context context,
final long feedID, final String query) {
return new FutureTask<>(new QueryTask<List<FeedItem>>(context) {
@Override
public void execute(PodDBAdapter adapter) {
- Cursor searchResult = adapter.searchItemTitles(feedID,
- query);
- List<FeedItem> items = DBReader.extractItemlistFromCursor(searchResult);
- DBReader.loadAdditionalFeedItemListData(items);
- setResult(items);
- searchResult.close();
- }
- });
- }
-
- /**
- * Searches the authors of FeedItems of a specific Feed for a given
- * string.
- *
- * @param context Used for accessing the DB.
- * @param feedID The id of the feed whose items should be searched.
- * @param query The search string.
- * @return A FutureTask object that executes the search request and returns the search result as a List of FeedItems.
- */
- public static FutureTask<List<FeedItem>> searchFeedItemAuthor(final Context context,
- final long feedID, final String query) {
- return new FutureTask<>(new QueryTask<List<FeedItem>>(context) {
- @Override
- public void execute(PodDBAdapter adapter) {
- Cursor searchResult = adapter.searchItemAuthors(feedID,
- query);
- List<FeedItem> items = DBReader.extractItemlistFromCursor(searchResult);
- DBReader.loadAdditionalFeedItemListData(items);
- setResult(items);
- searchResult.close();
- }
- });
- }
-
- /**
- * Searches the feed identifiers of FeedItems of a specific Feed for a given
- * string.
- *
- * @param context Used for accessing the DB.
- * @param feedID The id of the feed whose items should be searched.
- * @param query The search string.
- * @return A FutureTask object that executes the search request and returns the search result as a List of FeedItems.
- */
- public static FutureTask<List<FeedItem>> searchFeedItemFeedIdentifier(final Context context,
- final long feedID, final String query) {
- return new FutureTask<>(new QueryTask<List<FeedItem>>(context) {
- @Override
- public void execute(PodDBAdapter adapter) {
- Cursor searchResult = adapter.searchItemFeedIdentifiers(feedID,
- query);
- List<FeedItem> items = DBReader.extractItemlistFromCursor(searchResult);
- DBReader.loadAdditionalFeedItemListData(items);
- setResult(items);
- searchResult.close();
- }
- });
- }
-
- /**
- * Searches the descriptions of FeedItems of a specific Feed for a given
- * string.
- *
- * @param context Used for accessing the DB.
- * @param feedID The id of the feed whose items should be searched.
- * @param query The search string
- * @return A FutureTask object that executes the search request and returns the search result as a List of FeedItems.
- */
- public static FutureTask<List<FeedItem>> searchFeedItemDescription(final Context context,
- final long feedID, final String query) {
- return new FutureTask<>(new QueryTask<List<FeedItem>>(context) {
- @Override
- public void execute(PodDBAdapter adapter) {
- Cursor searchResult = adapter.searchItemDescriptions(feedID,
- query);
- List<FeedItem> items = DBReader.extractItemlistFromCursor(searchResult);
- DBReader.loadAdditionalFeedItemListData(items);
- setResult(items);
- searchResult.close();
- }
- });
- }
-
- /**
- * Searches the contentEncoded-value of FeedItems of a specific Feed for a given
- * string.
- *
- * @param context Used for accessing the DB.
- * @param feedID The id of the feed whose items should be searched.
- * @param query The search string
- * @return A FutureTask object that executes the search request and returns the search result as a List of FeedItems.
- */
- public static FutureTask<List<FeedItem>> searchFeedItemContentEncoded(final Context context,
- final long feedID, final String query) {
- return new FutureTask<>(new QueryTask<List<FeedItem>>(context) {
- @Override
- public void execute(PodDBAdapter adapter) {
- Cursor searchResult = adapter.searchItemContentEncoded(feedID,
- query);
- List<FeedItem> items = DBReader.extractItemlistFromCursor(searchResult);
- DBReader.loadAdditionalFeedItemListData(items);
- setResult(items);
- searchResult.close();
- }
- });
- }
-
- /**
- * Searches chapters of the FeedItems of a specific Feed for a given string.
- *
- * @param context Used for accessing the DB.
- * @param feedID The id of the feed whose items should be searched.
- * @param query The search string
- * @return A FutureTask object that executes the search request and returns the search result as a List of FeedItems.
- */
- public static FutureTask<List<FeedItem>> searchFeedItemChapters(final Context context,
- final long feedID, final String query) {
- return new FutureTask<>(new QueryTask<List<FeedItem>>(context) {
- @Override
- public void execute(PodDBAdapter adapter) {
- Cursor searchResult = adapter.searchItemChapters(feedID,
- query);
+ Cursor searchResult = adapter.searchItems(feedID, query);
List<FeedItem> items = DBReader.extractItemlistFromCursor(searchResult);
DBReader.loadAdditionalFeedItemListData(items);
setResult(items);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java b/core/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java
index 0c8d20007..1d9e33d0e 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java
@@ -3,6 +3,7 @@ package de.danoeh.antennapod.core.storage;
import android.content.Context;
import androidx.annotation.NonNull;
+import de.danoeh.antennapod.core.feed.Chapter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
@@ -17,13 +18,12 @@ import de.danoeh.antennapod.core.feed.SearchResult;
import de.danoeh.antennapod.core.util.comparator.InReverseChronologicalOrder;
/**
- * Performs search on Feeds and FeedItems
+ * Performs search on Feeds and FeedItems.
*/
public class FeedSearcher {
- private FeedSearcher(){}
-
- private static final String TAG = "FeedSearcher";
+ private FeedSearcher() {
+ }
/**
* Search through a feed, or all feeds, for episodes that match the query in either the title,
@@ -31,52 +31,54 @@ public class FeedSearcher {
* show notes. The list of resulting episodes also describes where the first match occurred
* (title, chapters, or show notes).
*
- * @param context
+ * @param context Used for database access
* @param query search query
* @param selectedFeed feed to search, 0 to search through all feeds
* @return list of episodes containing the query
*/
@NonNull
- public static List<SearchResult> performSearch(final Context context,
- final String query, final long selectedFeed) {
- final int values[] = {2, 1, 0, 0, 0, 0};
- final String[] subtitles = {context.getString(R.string.found_in_title_label),
- context.getString(R.string.found_in_chapters_label),
- context.getString(R.string.found_in_shownotes_label),
- context.getString(R.string.found_in_shownotes_label),
- context.getString(R.string.found_in_authors_label),
- context.getString(R.string.found_in_feeds_label)};
-
+ public static List<SearchResult> performSearch(final Context context, final String query, final long selectedFeed) {
final List<SearchResult> result = new ArrayList<>();
-
- List<FutureTask<List<FeedItem>>> tasks = new ArrayList<>();
- tasks.add(DBTasks.searchFeedItemTitle(context, selectedFeed, query));
- tasks.add(DBTasks.searchFeedItemChapters(context, selectedFeed, query));
- tasks.add(DBTasks.searchFeedItemDescription(context, selectedFeed, query));
- tasks.add(DBTasks.searchFeedItemContentEncoded(context, selectedFeed, query));
- tasks.add(DBTasks.searchFeedItemAuthor(context, selectedFeed, query));
- tasks.add(DBTasks.searchFeedItemFeedIdentifier(context, selectedFeed, query));
-
- for (FutureTask<List<FeedItem>> task : tasks) {
- task.run();
- }
try {
- Set<Long> set = new HashSet<>();
-
- for (int i = 0; i < tasks.size(); i++) {
- FutureTask<List<FeedItem>> task = tasks.get(i);
- List<FeedItem> items = task.get();
- for (FeedItem item : items) {
- if (!set.contains(item.getId())) { // to prevent duplicate results
- result.add(new SearchResult(item, values[i], subtitles[i]));
- set.add(item.getId());
- }
+ FutureTask<List<FeedItem>> searchTask = DBTasks.searchFeedItems(context, selectedFeed, query);
+ searchTask.run();
+ final List<FeedItem> items = searchTask.get();
+ for (FeedItem item : items) {
+ SearchLocation location;
+ if (safeContains(item.getTitle(), query)) {
+ location = SearchLocation.TITLE;
+ } else if (safeContains(item.getContentEncoded(), query)) {
+ location = SearchLocation.SHOWNOTES;
+ } else if (safeContains(item.getDescription(), query)) {
+ location = SearchLocation.SHOWNOTES;
+ } else if (safeContains(item.getChapters(), query)) {
+ location = SearchLocation.CHAPTERS;
+ } else if (safeContains(item.getFeed().getAuthor(), query)) {
+ location = SearchLocation.AUTHORS;
+ } else {
+ location = SearchLocation.FEED;
}
+ result.add(new SearchResult(item, location));
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
- Collections.sort(result, new InReverseChronologicalOrder());
return result;
}
+
+ private static boolean safeContains(String haystack, String needle) {
+ return haystack != null && haystack.contains(needle);
+ }
+
+ private static boolean safeContains(List<Chapter> haystack, String needle) {
+ if (haystack == null) {
+ return false;
+ }
+ for (Chapter chapter : haystack) {
+ if (safeContains(chapter.getTitle(), needle)) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
index 1aff73564..96c3a46da 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
@@ -1290,133 +1290,39 @@ public class PodDBAdapter {
}
/**
- * Searches for the given query in the description of all items or the items
+ * Searches for the given query in various values of all items or the items
* of a specified feed.
*
* @return A cursor with all search results in SEL_FI_EXTRA selection.
*/
- public Cursor searchItemDescriptions(long feedID, String query) {
- if (feedID != 0) {
- // search items in specific feed
- return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_FEED
- + "=? AND " + KEY_DESCRIPTION + " LIKE '%"
- + prepareSearchQuery(query) + "%'",
- new String[]{String.valueOf(feedID)}, null, null,
- null
- );
- } else {
- // search through all items
- return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL,
- KEY_DESCRIPTION + " LIKE '%" + prepareSearchQuery(query)
- + "%'", null, null, null, null
- );
- }
- }
+ public Cursor searchItems(long feedID, String searchQuery) {
+ String preparedQuery = prepareSearchQuery(searchQuery);
- /**
- * Searches for the given query in the content-encoded field of all items or
- * the items of a specified feed.
- *
- * @return A cursor with all search results in SEL_FI_EXTRA selection.
- */
- public Cursor searchItemContentEncoded(long feedID, String query) {
+ String queryFeedId = "";
if (feedID != 0) {
// search items in specific feed
- return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_FEED
- + "=? AND " + KEY_CONTENT_ENCODED + " LIKE '%"
- + prepareSearchQuery(query) + "%'",
- new String[]{String.valueOf(feedID)}, null, null,
- null
- );
+ queryFeedId = KEY_FEED + " = " + feedID;
} else {
// search through all items
- return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL,
- KEY_CONTENT_ENCODED + " LIKE '%"
- + prepareSearchQuery(query) + "%'", null, null,
- null, null
- );
+ queryFeedId = "1 = 1";
}
- }
- public Cursor searchItemTitles(long feedID, String query) {
- if (feedID != 0) {
- // search items in specific feed
- return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_FEED
- + "=? AND " + KEY_TITLE + " LIKE '%"
- + prepareSearchQuery(query) + "%'",
- new String[]{String.valueOf(feedID)}, null, null,
- null
- );
- } else {
- // search through all items
- return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL,
- KEY_TITLE + " LIKE '%"
- + prepareSearchQuery(query) + "%'", null, null,
- null, null
- );
- }
- }
-
- public Cursor searchItemAuthors(long feedID, String query) {
- if (feedID != 0) {
- // search items in specific feed
- return db.rawQuery("SELECT " + TextUtils.join(", ", FEEDITEM_SEL_FI_SMALL) + " FROM " + TABLE_NAME_FEED_ITEMS
- + " JOIN " + TABLE_NAME_FEEDS + " ON " + TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + "=" + TABLE_NAME_FEEDS + "." + KEY_ID
- + " WHERE " + KEY_FEED
- + "=? AND " + KEY_AUTHOR + " LIKE '%"
- + prepareSearchQuery(query) + "%' ORDER BY "
- + TABLE_NAME_FEED_ITEMS + "." + KEY_PUBDATE + " DESC",
- new String[]{String.valueOf(feedID)}
- );
- } else {
- // search through all items
- return db.rawQuery("SELECT " + TextUtils.join(", ", FEEDITEM_SEL_FI_SMALL) + " FROM " + TABLE_NAME_FEED_ITEMS
- + " JOIN " + TABLE_NAME_FEEDS + " ON " + TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + "=" + TABLE_NAME_FEEDS + "." + KEY_ID
- + " WHERE " + KEY_AUTHOR + " LIKE '%"
- + prepareSearchQuery(query) + "%' ORDER BY "
- + TABLE_NAME_FEED_ITEMS + "." + KEY_PUBDATE + " DESC",
- null
- );
- }
- }
-
- public Cursor searchItemFeedIdentifiers(long feedID, String query) {
- if (feedID != 0) {
- // search items in specific feed
- return db.rawQuery("SELECT " + TextUtils.join(", ", FEEDITEM_SEL_FI_SMALL) + " FROM " + TABLE_NAME_FEED_ITEMS
- + " JOIN " + TABLE_NAME_FEEDS + " ON " + TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + "=" + TABLE_NAME_FEEDS + "." + KEY_ID
- + " WHERE " + KEY_FEED
- + "=? AND " + KEY_FEED_IDENTIFIER + " LIKE '%"
- + prepareSearchQuery(query) + "%' ORDER BY "
- + TABLE_NAME_FEED_ITEMS + "." + KEY_PUBDATE + " DESC",
- new String[]{String.valueOf(feedID)}
- );
- } else {
- // search through all items
- return db.rawQuery("SELECT " + TextUtils.join(", ", FEEDITEM_SEL_FI_SMALL) + " FROM " + TABLE_NAME_FEED_ITEMS
- + " JOIN " + TABLE_NAME_FEEDS + " ON " + TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + "=" + TABLE_NAME_FEEDS + "." + KEY_ID
- + " WHERE " + KEY_FEED_IDENTIFIER + " LIKE '%"
- + prepareSearchQuery(query) + "%' ORDER BY "
- + TABLE_NAME_FEED_ITEMS + "." + KEY_PUBDATE + " DESC",
- null
- );
- }
- }
-
- public Cursor searchItemChapters(long feedID, String searchQuery) {
- final String query;
- if (feedID != 0) {
- query = "SELECT " + SEL_FI_SMALL_STR + " FROM " + TABLE_NAME_FEED_ITEMS + " INNER JOIN " +
- TABLE_NAME_SIMPLECHAPTERS + " ON " + TABLE_NAME_SIMPLECHAPTERS + "." + KEY_FEEDITEM + "=" +
- TABLE_NAME_FEED_ITEMS + "." + KEY_ID + " WHERE " + TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + "=" +
- feedID + " AND " + TABLE_NAME_SIMPLECHAPTERS + "." + KEY_TITLE + " LIKE '%"
- + prepareSearchQuery(searchQuery) + "%'";
- } else {
- query = "SELECT " + SEL_FI_SMALL_STR + " FROM " + TABLE_NAME_FEED_ITEMS + " INNER JOIN " +
- TABLE_NAME_SIMPLECHAPTERS + " ON " + TABLE_NAME_SIMPLECHAPTERS + "." + KEY_FEEDITEM + "=" +
- TABLE_NAME_FEED_ITEMS + "." + KEY_ID + " WHERE " + TABLE_NAME_SIMPLECHAPTERS + "." + KEY_TITLE + " LIKE '%"
- + prepareSearchQuery(searchQuery) + "%'";
- }
+ String query = "SELECT " + SEL_FI_SMALL_STR + " FROM " + TABLE_NAME_FEED_ITEMS
+ + " LEFT JOIN " + TABLE_NAME_SIMPLECHAPTERS
+ + " ON " + TABLE_NAME_SIMPLECHAPTERS + "." + KEY_FEEDITEM
+ + "=" + TABLE_NAME_FEED_ITEMS + "." + KEY_ID
+ + " LEFT JOIN " + TABLE_NAME_FEEDS
+ + " ON " + TABLE_NAME_FEED_ITEMS + "." + KEY_FEED
+ + "=" + TABLE_NAME_FEEDS + "." + KEY_ID
+ + " WHERE " + queryFeedId + " AND ("
+ + TABLE_NAME_FEED_ITEMS + "." + KEY_DESCRIPTION + " LIKE '%" + preparedQuery + "%' OR "
+ + TABLE_NAME_FEED_ITEMS + "." + KEY_CONTENT_ENCODED + " LIKE '%" + preparedQuery + "%' OR "
+ + TABLE_NAME_FEED_ITEMS + "." + KEY_TITLE + " LIKE '%" + preparedQuery + "%' OR "
+ + TABLE_NAME_SIMPLECHAPTERS + "." + KEY_TITLE + " LIKE '%" + preparedQuery + "%' OR "
+ + TABLE_NAME_FEEDS + "." + KEY_AUTHOR + " LIKE '%" + preparedQuery + "%' OR "
+ + TABLE_NAME_FEEDS + "." + KEY_FEED_IDENTIFIER + " LIKE '%" + preparedQuery + "%'"
+ + ") ORDER BY " + KEY_PUBDATE + " DESC "
+ + "LIMIT 500";
return db.rawQuery(query, null);
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/SearchLocation.java b/core/src/main/java/de/danoeh/antennapod/core/storage/SearchLocation.java
new file mode 100644
index 000000000..fabe85b2c
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/SearchLocation.java
@@ -0,0 +1,21 @@
+package de.danoeh.antennapod.core.storage;
+
+import androidx.annotation.StringRes;
+import de.danoeh.antennapod.core.R;
+
+public enum SearchLocation {
+ TITLE(R.string.found_in_title_label),
+ CHAPTERS(R.string.found_in_chapters_label),
+ SHOWNOTES(R.string.found_in_shownotes_label),
+ AUTHORS(R.string.found_in_authors_label),
+ FEED(R.string.found_in_feeds_label);
+
+ private int description;
+ SearchLocation(@StringRes int description) {
+ this.description = description;
+ }
+
+ public @StringRes int getDescription() {
+ return description;
+ }
+}