]> source.dussan.org Git - gitblit.git/commitdiff
Use reflection to determine source repository index
authorJames Moger <james.moger@gitblit.com>
Thu, 15 Mar 2012 23:46:32 +0000 (19:46 -0400)
committerJames Moger <james.moger@gitblit.com>
Thu, 15 Mar 2012 23:46:32 +0000 (19:46 -0400)
Unfortunately Lucene's MultiReader class does not expose a public method
for determining which index reader a document comes from.  There is a
private method which determines this information.

My new approach is to use reflection to call this private method and
determine the actual source index at runtime instead of storing the
repository name in the index. This gets me out of the "rename
repository" problem at the expense of a little runtime performance.

src/com/gitblit/LuceneExecutor.java

index 527609e9bbacbd07a6d3667764aa8b746cfee4fe..3b8c2b4f29048f87a5f78fb5c1239d6e34662987 100644 (file)
@@ -21,6 +21,7 @@ import java.io.ByteArrayOutputStream;
 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
@@ -103,14 +104,13 @@ import com.gitblit.utils.StringUtils;
 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
@@ -335,6 +335,24 @@ public class LuceneExecutor implements Runnable {
                }\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
@@ -501,7 +519,6 @@ public class LuceneExecutor implements Runnable {
                                                \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
@@ -542,7 +559,6 @@ public class LuceneExecutor implements Runnable {
                                // 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
@@ -557,7 +573,6 @@ public class LuceneExecutor implements Runnable {
                                        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
@@ -577,7 +592,6 @@ public class LuceneExecutor implements Runnable {
                                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
@@ -594,24 +608,6 @@ public class LuceneExecutor implements Runnable {
                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
@@ -659,7 +655,6 @@ public class LuceneExecutor implements Runnable {
                                        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
@@ -844,7 +839,7 @@ public class LuceneExecutor implements Runnable {
                }\r
                return result;\r
        }\r
-\r
+       \r
        /**\r
         * Creates a Lucene document from an issue.\r
         * \r
@@ -906,7 +901,6 @@ public class LuceneExecutor implements Runnable {
         */\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
@@ -926,7 +920,6 @@ public class LuceneExecutor implements Runnable {
                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
@@ -1057,7 +1050,7 @@ public class LuceneExecutor implements Runnable {
                                        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
@@ -1067,8 +1060,17 @@ public class LuceneExecutor implements Runnable {
                        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
@@ -1188,4 +1190,38 @@ public class LuceneExecutor implements Runnable {
                        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