尝试与lucene进行更多匹配
Trying to get more matches with lucene
我正在使用 Java 和 lucene 来匹配我从服务收到的列表中的每首歌曲和本地文件。我目前正在苦苦挣扎的是找到一个查询,该查询将使我获得每首歌曲尽可能多的匹配项。如果每首歌至少能得到一个匹配的文件,那就太好了。
这是我的 atm:
public List<String> getMatchesForSong(String artist, String title, String album) throws ParseException, IOException {
StandardAnalyzer analyzer = new StandardAnalyzer();
String defaultQuery = "(title: \"%s\"~2) AND ((artist: \"%s\") OR (album: \"%s\"))";
String searchQuery = String.format(defaultQuery, title, artist, album);
Query query = new QueryParser("title", analyzer).parse(searchQuery);
if (indexWriter == null) {
indexWriter = createIndexWriter(indexDir);
indexSearcher = createIndexSearcher(indexWriter);
}
TopDocs topDocs = indexSearcher.search(query, 20);
if (topDocs.totalHits > 0) {
return parseScoreDocsList(topDocs.scoreDocs);
}
return null;
}
如果没有不一致,即使是 non-English 个字符,这种方法也能很好地工作。但它不会 return 我一个单一的匹配,例如,如果我收到一首标题为 "The Sun Was In My Eyes: Part One" 的歌曲,但我相应的文件有标题 "The Sun Was In My Eyes: Part 1",或者如果我收到它"Pt. 1".
我也没有找到匹配项,当标题的字数比相应的文件多时,例如 "The End of all Times (Martyrs Fire)" 与 "The End of all Times" 相对。专辑名称也可能发生。
所以,我想知道我应该对我的代码进行哪些改进,以获得更多的匹配。
所以我最终发现对标题或专辑使用 PhraseQuery 并不是最好的方法,因为这会导致 lucene 搜索精确的此类短语。
我最后做的是为标题和专辑的每个单词创建一个 TermQuery,然后将所有内容加入 BooleanQuery。
private Query parseQueryForSong(String artist, String title, String album) throws ParseException {
String[] artistArr = artist.split(" ");
String[] titleArr = sanitizePhrase(title).split(" ");
String[] albumArr = sanitizePhrase(album).split(" ");
BooleanQuery.Builder mainQueryBuilder = new BooleanQuery.Builder();
BooleanQuery.Builder albumQueryBuilder = new BooleanQuery.Builder();
PhraseQuery artistQuery = new PhraseQuery("artist", artistArr);
for (String titleWord : titleArr) {
if (!titleWord.isEmpty()) {
mainQueryBuilder.add(new TermQuery(new Term("title", titleWord)), BooleanClause.Occur.SHOULD);
}
}
for (String albumWord : albumArr) {
if (!albumWord.isEmpty()) {
albumQueryBuilder.add(new TermQuery(new Term("album", albumWord)), BooleanClause.Occur.SHOULD);
}
}
mainQueryBuilder.add(artistQuery, BooleanClause.Occur.MUST);
mainQueryBuilder.add(albumQueryBuilder.build(), BooleanClause.Occur.MUST);
StandardAnalyzer analyzer = new StandardAnalyzer();
Query mainQuery = new QueryParser("title", analyzer).parse(mainQueryBuilder.build().toString());
return mainQuery;
}
我正在使用 Java 和 lucene 来匹配我从服务收到的列表中的每首歌曲和本地文件。我目前正在苦苦挣扎的是找到一个查询,该查询将使我获得每首歌曲尽可能多的匹配项。如果每首歌至少能得到一个匹配的文件,那就太好了。
这是我的 atm:
public List<String> getMatchesForSong(String artist, String title, String album) throws ParseException, IOException {
StandardAnalyzer analyzer = new StandardAnalyzer();
String defaultQuery = "(title: \"%s\"~2) AND ((artist: \"%s\") OR (album: \"%s\"))";
String searchQuery = String.format(defaultQuery, title, artist, album);
Query query = new QueryParser("title", analyzer).parse(searchQuery);
if (indexWriter == null) {
indexWriter = createIndexWriter(indexDir);
indexSearcher = createIndexSearcher(indexWriter);
}
TopDocs topDocs = indexSearcher.search(query, 20);
if (topDocs.totalHits > 0) {
return parseScoreDocsList(topDocs.scoreDocs);
}
return null;
}
如果没有不一致,即使是 non-English 个字符,这种方法也能很好地工作。但它不会 return 我一个单一的匹配,例如,如果我收到一首标题为 "The Sun Was In My Eyes: Part One" 的歌曲,但我相应的文件有标题 "The Sun Was In My Eyes: Part 1",或者如果我收到它"Pt. 1".
我也没有找到匹配项,当标题的字数比相应的文件多时,例如 "The End of all Times (Martyrs Fire)" 与 "The End of all Times" 相对。专辑名称也可能发生。
所以,我想知道我应该对我的代码进行哪些改进,以获得更多的匹配。
所以我最终发现对标题或专辑使用 PhraseQuery 并不是最好的方法,因为这会导致 lucene 搜索精确的此类短语。
我最后做的是为标题和专辑的每个单词创建一个 TermQuery,然后将所有内容加入 BooleanQuery。
private Query parseQueryForSong(String artist, String title, String album) throws ParseException {
String[] artistArr = artist.split(" ");
String[] titleArr = sanitizePhrase(title).split(" ");
String[] albumArr = sanitizePhrase(album).split(" ");
BooleanQuery.Builder mainQueryBuilder = new BooleanQuery.Builder();
BooleanQuery.Builder albumQueryBuilder = new BooleanQuery.Builder();
PhraseQuery artistQuery = new PhraseQuery("artist", artistArr);
for (String titleWord : titleArr) {
if (!titleWord.isEmpty()) {
mainQueryBuilder.add(new TermQuery(new Term("title", titleWord)), BooleanClause.Occur.SHOULD);
}
}
for (String albumWord : albumArr) {
if (!albumWord.isEmpty()) {
albumQueryBuilder.add(new TermQuery(new Term("album", albumWord)), BooleanClause.Occur.SHOULD);
}
}
mainQueryBuilder.add(artistQuery, BooleanClause.Occur.MUST);
mainQueryBuilder.add(albumQueryBuilder.build(), BooleanClause.Occur.MUST);
StandardAnalyzer analyzer = new StandardAnalyzer();
Query mainQuery = new QueryParser("title", analyzer).parse(mainQueryBuilder.build().toString());
return mainQuery;
}