* improved search result auto-selection

This commit is contained in:
Reinhard Pointner 2011-11-29 08:56:29 +00:00
parent cc73f42b6b
commit 151c43028d
2 changed files with 32 additions and 15 deletions

View File

@ -63,7 +63,7 @@ public class Main {
if (args.clearUserData()) { if (args.clearUserData()) {
// clear preferences and cache // clear preferences and cache
System.out.println("Reset preferences and clear cache."); System.out.println("Reset preferences and clear cache");
Settings.forPackage(Main.class).clear(); Settings.forPackage(Main.class).clear();
CacheManager.getInstance().clearAll(); CacheManager.getInstance().clearAll();
} }

View File

@ -20,6 +20,7 @@ import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
@ -198,13 +199,16 @@ public class CmdlineOperations implements CmdlineInterface {
// select search result // select search result
if (results.size() > 0) { if (results.size() > 0) {
SearchResult selectedSearchResult = selectSearchResult(query, results, strict); List<SearchResult> selectedSearchResults = selectSearchResult(query, results, strict);
if (selectedSearchResult != null) { if (selectedSearchResults != null) {
CLILogger.fine(format("Fetching episode data for [%s]", selectedSearchResult.getName())); List<Episode> episodes = new ArrayList<Episode>();
List<Episode> episodes = db.getEpisodeList(selectedSearchResult, locale); for (SearchResult it : selectedSearchResults) {
CLILogger.fine(format("Fetching episode data for [%s]", it.getName()));
episodes.addAll(db.getEpisodeList(it, locale));
Analytics.trackEvent(db.getName(), "FetchEpisodeList", it.getName());
}
Analytics.trackEvent(db.getName(), "FetchEpisodeList", selectedSearchResult.getName());
return episodes; return episodes;
} }
} }
@ -258,7 +262,7 @@ public class CmdlineOperations implements CmdlineInterface {
// use user query if search by hash did not return any results, only one query for one movie though // use user query if search by hash did not return any results, only one query for one movie though
if (query != null && movieDescriptors.length == 1 && movieDescriptors[0] == null) { if (query != null && movieDescriptors.length == 1 && movieDescriptors[0] == null) {
CLILogger.fine(format("Looking up movie by query [%s]", query)); CLILogger.fine(format("Looking up movie by query [%s]", query));
movieDescriptors[0] = (Movie) selectSearchResult(query, db.searchMovie(query, locale), strict); movieDescriptors[0] = (Movie) selectSearchResult(query, db.searchMovie(query, locale), strict).get(0);
} }
// map old files to new paths by applying formatting and validating filenames // map old files to new paths by applying formatting and validating filenames
@ -563,35 +567,48 @@ public class CmdlineOperations implements CmdlineInterface {
} }
private Collection<SearchResult> findProbableMatches(String query, Iterable<? extends SearchResult> searchResults) { private List<SearchResult> findProbableMatches(final String query, Iterable<? extends SearchResult> searchResults) {
// auto-select most probable search result // auto-select most probable search result
Map<String, SearchResult> probableMatches = new TreeMap<String, SearchResult>(String.CASE_INSENSITIVE_ORDER); Map<String, SearchResult> probableMatches = new TreeMap<String, SearchResult>(String.CASE_INSENSITIVE_ORDER);
// use name similarity metric // use name similarity metric
SimilarityMetric metric = new NameSimilarityMetric(); final SimilarityMetric metric = new NameSimilarityMetric();
// find probable matches using name similarity > 0.9 // find probable matches using name similarity > 0.9
for (SearchResult result : searchResults) { for (SearchResult result : searchResults) {
if (metric.getSimilarity(query, result.getName()) > 0.9) { float f = metric.getSimilarity(query, result.getName());
if (f >= 0.9 || (f >= 0.6 && result.getName().toLowerCase().startsWith(query.toLowerCase()))) {
if (!probableMatches.containsKey(result.toString())) { if (!probableMatches.containsKey(result.toString())) {
probableMatches.put(result.toString(), result); probableMatches.put(result.toString(), result);
} }
} }
} }
return probableMatches.values(); // sort results by similarity to query
List<SearchResult> results = new ArrayList<SearchResult>(probableMatches.values());
sort(results, new Comparator<SearchResult>() {
@Override
public int compare(SearchResult o1, SearchResult o2) {
float f1 = metric.getSimilarity(o1.getName(), query);
float f2 = metric.getSimilarity(o2.getName(), query);
return f1 > f2 ? f1 == f2 ? 0 : -1 : 1;
}
});
return results;
} }
private SearchResult selectSearchResult(String query, Iterable<? extends SearchResult> searchResults, boolean strict) throws Exception { private List<SearchResult> selectSearchResult(String query, Iterable<? extends SearchResult> searchResults, boolean strict) throws Exception {
Collection<SearchResult> probableMatches = findProbableMatches(query, searchResults); List<SearchResult> probableMatches = findProbableMatches(query, searchResults);
if (probableMatches.isEmpty() || (strict && probableMatches.size() != 1)) { if (probableMatches.isEmpty() || (strict && probableMatches.size() != 1)) {
throw new Exception("Failed to auto-select search result: " + probableMatches); throw new Exception("Failed to auto-select search result: " + probableMatches);
} }
// return first and only value // return first and only value
return probableMatches.iterator().next(); return probableMatches;
} }
@ -773,7 +790,7 @@ public class CmdlineOperations implements CmdlineInterface {
EpisodeListProvider service = (db == null) ? TVRage : getEpisodeListProvider(db); EpisodeListProvider service = (db == null) ? TVRage : getEpisodeListProvider(db);
Locale locale = getLanguage(languageName).toLocale(); Locale locale = getLanguage(languageName).toLocale();
SearchResult hit = selectSearchResult(query, service.search(query, locale), false); SearchResult hit = selectSearchResult(query, service.search(query, locale), false).get(0);
List<String> episodes = new ArrayList<String>(); List<String> episodes = new ArrayList<String>();
for (Episode it : service.getEpisodeList(hit, locale)) { for (Episode it : service.getEpisodeList(hit, locale)) {