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