import java.io.File;\r
import java.io.IOException;\r
import java.io.InputStream;\r
+import java.lang.reflect.Method;\r
import java.text.MessageFormat;\r
import java.text.ParseException;\r
import java.util.ArrayList;\r
public class LuceneExecutor implements Runnable {\r
\r
\r
- private static final int INDEX_VERSION = 1;\r
+ private static final int INDEX_VERSION = 2;\r
\r
private static final String FIELD_OBJECT_TYPE = "type";\r
private static final String FIELD_ISSUE = "issue";\r
private static final String FIELD_PATH = "path";\r
private static final String FIELD_COMMIT = "commit";\r
private static final String FIELD_BRANCH = "branch";\r
- private static final String FIELD_REPOSITORY = "repository";\r
private static final String FIELD_SUMMARY = "summary";\r
private static final String FIELD_CONTENT = "content";\r
private static final String FIELD_AUTHOR = "author";\r
}\r
return name;\r
}\r
+ \r
+ /**\r
+ * Get the tree associated with the given commit.\r
+ *\r
+ * @param walk\r
+ * @param commit\r
+ * @return tree\r
+ * @throws IOException\r
+ */\r
+ protected RevTree getTree(final RevWalk walk, final RevCommit commit)\r
+ throws IOException {\r
+ final RevTree tree = commit.getTree();\r
+ if (tree != null) {\r
+ return tree;\r
+ }\r
+ walk.parseHeaders(commit);\r
+ return commit.getTree();\r
+ }\r
\r
/**\r
* Construct a keyname from the branch.\r
\r
Document doc = new Document();\r
doc.add(new Field(FIELD_OBJECT_TYPE, SearchObjectType.blob.name(), Store.YES, Index.NOT_ANALYZED_NO_NORMS));\r
- doc.add(new Field(FIELD_REPOSITORY, repositoryName, Store.YES, Index.ANALYZED));\r
doc.add(new Field(FIELD_BRANCH, branchName, Store.YES, Index.ANALYZED));\r
doc.add(new Field(FIELD_COMMIT, commit.getName(), Store.YES, Index.ANALYZED));\r
doc.add(new Field(FIELD_PATH, path, Store.YES, Index.ANALYZED));\r
// index the tip commit object\r
if (indexedCommits.add(tipId)) {\r
Document doc = createDocument(tip, tags.get(tipId));\r
- doc.add(new Field(FIELD_REPOSITORY, repositoryName, Store.YES, Index.ANALYZED));\r
doc.add(new Field(FIELD_BRANCH, branchName, Store.YES, Index.ANALYZED));\r
writer.addDocument(doc);\r
result.commitCount += 1;\r
String hash = rev.getId().getName();\r
if (indexedCommits.add(hash)) {\r
Document doc = createDocument(rev, tags.get(hash));\r
- doc.add(new Field(FIELD_REPOSITORY, repositoryName, Store.YES, Index.ANALYZED));\r
doc.add(new Field(FIELD_BRANCH, branchName, Store.YES, Index.ANALYZED));\r
writer.addDocument(doc);\r
result.commitCount += 1;\r
for (IssueModel issue : issues) {\r
result.issueCount++;\r
Document doc = createDocument(issue);\r
- doc.add(new Field(FIELD_REPOSITORY, repositoryName, Store.YES, Index.ANALYZED));\r
writer.addDocument(doc);\r
}\r
}\r
return result;\r
}\r
\r
- /**\r
- * Get the tree associated with the given commit.\r
- *\r
- * @param walk\r
- * @param commit\r
- * @return tree\r
- * @throws IOException\r
- */\r
- protected RevTree getTree(final RevWalk walk, final RevCommit commit)\r
- throws IOException {\r
- final RevTree tree = commit.getTree();\r
- if (tree != null) {\r
- return tree;\r
- }\r
- walk.parseHeaders(commit);\r
- return commit.getTree();\r
- }\r
-\r
/**\r
* Incrementally update the index with the specified commit for the\r
* repository.\r
Document doc = new Document();\r
doc.add(new Field(FIELD_OBJECT_TYPE, SearchObjectType.blob.name(), Store.YES,\r
Index.NOT_ANALYZED));\r
- doc.add(new Field(FIELD_REPOSITORY, repositoryName, Store.YES, Index.ANALYZED));\r
doc.add(new Field(FIELD_BRANCH, branch, Store.YES, Index.ANALYZED));\r
doc.add(new Field(FIELD_COMMIT, commit.getName(), Store.YES, Index.ANALYZED));\r
doc.add(new Field(FIELD_PATH, path.path, Store.YES, Index.ANALYZED));\r
}\r
return result;\r
}\r
-\r
+ \r
/**\r
* Creates a Lucene document from an issue.\r
* \r
*/\r
private boolean index(String repositoryName, Document doc) {\r
try { \r
- doc.add(new Field(FIELD_REPOSITORY, repositoryName, Store.YES, Index.NOT_ANALYZED));\r
IndexWriter writer = getIndexWriter(repositoryName);\r
writer.addDocument(doc);\r
resetIndexSearcher(repositoryName);\r
result.author = doc.get(FIELD_AUTHOR);\r
result.committer = doc.get(FIELD_COMMITTER);\r
result.type = SearchObjectType.fromName(doc.get(FIELD_OBJECT_TYPE));\r
- result.repository = doc.get(FIELD_REPOSITORY);\r
result.branch = doc.get(FIELD_BRANCH);\r
result.commitId = doc.get(FIELD_COMMIT);\r
result.issueId = doc.get(FIELD_ISSUE);\r
readers.add(repositoryIndex.getIndexReader());\r
}\r
IndexReader[] rdrs = readers.toArray(new IndexReader[readers.size()]);\r
- MultiReader reader = new MultiReader(rdrs);\r
+ MultiSourceReader reader = new MultiSourceReader(rdrs);\r
searcher = new IndexSearcher(reader);\r
}\r
Query rewrittenQuery = searcher.rewrite(query);\r
for (int i = 0; i < hits.length; i++) {\r
int docId = hits[i].doc;\r
Document doc = searcher.doc(docId);\r
- // TODO identify the source index for the doc, then eliminate FIELD_REPOSITORY\r
+ // TODO identify the source index for the doc, then eliminate FIELD_REPOSITORY \r
SearchResult result = createSearchResult(doc, hits[i].score);\r
+ if (repositories.length == 1) {\r
+ // single repository search\r
+ result.repository = repositories[0];\r
+ } else {\r
+ // multi-repository search\r
+ MultiSourceReader reader = (MultiSourceReader) searcher.getIndexReader();\r
+ int index = reader.getSourceIndex(docId);\r
+ result.repository = repositories[index];\r
+ }\r
String content = doc.get(FIELD_CONTENT); \r
result.fragment = getHighlightedFragment(analyzer, query, content, result);\r
results.add(result);\r
return (endTime - startTime)/1000f;\r
}\r
}\r
+ \r
+ /**\r
+ * Custom subclass of MultiReader to identify the source index for a given\r
+ * doc id. This would not be necessary of there was a public method to\r
+ * obtain this information.\r
+ * \r
+ */\r
+ private class MultiSourceReader extends MultiReader {\r
+ \r
+ final Method method;\r
+ \r
+ MultiSourceReader(IndexReader[] subReaders) {\r
+ super(subReaders);\r
+ Method m = null;\r
+ try {\r
+ m = MultiReader.class.getDeclaredMethod("readerIndex", int.class);\r
+ m.setAccessible(true);\r
+ } catch (Exception e) {\r
+ logger.error("Error getting readerIndex method", e);\r
+ }\r
+ method = m;\r
+ }\r
+ \r
+ int getSourceIndex(int docId) {\r
+ int index = -1;\r
+ try {\r
+ Object o = method.invoke(this, docId);\r
+ index = (Integer) o;\r
+ } catch (Exception e) {\r
+ logger.error("Error getting source index", e);\r
+ }\r
+ return index;\r
+ }\r
+ }\r
}\r