From 7da05e7cd45d8314072a2d1f8829abd78435a0bc Mon Sep 17 00:00:00 2001 From: "Maria Odea B. Ching" Date: Wed, 16 Jul 2008 08:46:38 +0000 Subject: [PATCH] [MRM-864] -use a lucene Filter with BooleanQuery and the LuceneQuery for searching within the search results -added a checkbox in the general search page to search from the results only -maintain a list of previous query strings if searchResultsOnly option is enabled in general search git-svn-id: https://svn.apache.org/repos/asf/archiva/trunk@677197 13f79535-47bb-0310-9956-ffa450edef68 --- .../indexer/search/CrossRepositorySearch.java | 13 +++ .../search/DefaultCrossRepositorySearch.java | 53 ++++++++++-- .../DefaultCrossRepositorySearchTest.java | 57 +++++++++++-- .../archiva/web/action/SearchAction.java | 84 ++++++++++++++++++- .../WEB-INF/jsp/include/quickSearchForm.jspf | 2 + .../src/main/webapp/WEB-INF/jsp/results.jsp | 2 + 6 files changed, 196 insertions(+), 15 deletions(-) diff --git a/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/CrossRepositorySearch.java b/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/CrossRepositorySearch.java index 73c8cf61a..63e21151c 100644 --- a/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/CrossRepositorySearch.java +++ b/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/CrossRepositorySearch.java @@ -39,6 +39,19 @@ public interface CrossRepositorySearch */ public SearchResults searchForTerm( String principal, List selectedRepos, String term, SearchResultLimits limits ); + /** + * Search for a specific term from the previous search results. + * + * @param principal the user doing the search. + * @param selectedRepos the repositories to search from. + * @param term the term to search for. + * @param limits the limits to apply to the search results. + * @param previousSearchTerms the list of the previous search terms. + * @return the results + */ + public SearchResults searchForTerm( String principal, List selectedRepos, String term, + SearchResultLimits limits, List previousSearchTerms ); + /** * Search for the specific bytecode across all repositories. * diff --git a/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/DefaultCrossRepositorySearch.java b/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/DefaultCrossRepositorySearch.java index a2c813a19..8565acc46 100644 --- a/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/DefaultCrossRepositorySearch.java +++ b/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/DefaultCrossRepositorySearch.java @@ -27,8 +27,12 @@ import org.apache.lucene.document.Document; import org.apache.lucene.queryParser.MultiFieldQueryParser; import org.apache.lucene.queryParser.ParseException; import org.apache.lucene.queryParser.QueryParser; +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.Filter; import org.apache.lucene.search.Hits; import org.apache.lucene.search.MultiSearcher; +import org.apache.lucene.search.QueryWrapperFilter; import org.apache.lucene.search.Searchable; import org.apache.maven.archiva.configuration.ArchivaConfiguration; import org.apache.maven.archiva.configuration.ConfigurationNames; @@ -84,7 +88,7 @@ public class DefaultCrossRepositorySearch QueryParser parser = new MultiFieldQueryParser( new String[]{HashcodesKeys.MD5, HashcodesKeys.SHA1}, new HashcodesHandlers().getAnalyzer() ); LuceneQuery query = new LuceneQuery( parser.parse( checksum ) ); - SearchResults results = searchAll( query, limits, indexes ); + SearchResults results = searchAll( query, limits, indexes, null ); results.getRepositories().addAll( this.localIndexedRepositories ); return results; @@ -106,7 +110,7 @@ public class DefaultCrossRepositorySearch { QueryParser parser = new BytecodeHandlers().getQueryParser(); LuceneQuery query = new LuceneQuery( parser.parse( term ) ); - SearchResults results = searchAll( query, limits, indexes ); + SearchResults results = searchAll( query, limits, indexes, null ); results.getRepositories().addAll( this.localIndexedRepositories ); return results; @@ -120,7 +124,14 @@ public class DefaultCrossRepositorySearch return new SearchResults(); } + public SearchResults searchForTerm( String principal, List selectedRepos, String term, SearchResultLimits limits ) + { + return searchForTerm( principal, selectedRepos, term, limits, null ); + } + + public SearchResults searchForTerm( String principal, List selectedRepos, String term, + SearchResultLimits limits, List previousSearchTerms ) { List indexes = getFileContentIndexes( principal, selectedRepos ); List bytecodeIndices = getBytecodeIndexes( principal, selectedRepos ); @@ -129,8 +140,26 @@ public class DefaultCrossRepositorySearch try { QueryParser parser = new FileContentHandlers().getQueryParser(); - LuceneQuery query = new LuceneQuery( parser.parse( term ) ); - SearchResults results = searchAll( query, limits, indexes ); + LuceneQuery query = null; + SearchResults results = null; + if( previousSearchTerms == null || previousSearchTerms.isEmpty() ) + { + query = new LuceneQuery( parser.parse( term ) ); + results = searchAll( query, limits, indexes, null ); + } + else + { + // AND the previous search terms + BooleanQuery booleanQuery = new BooleanQuery(); + for( String previousSearchTerm : previousSearchTerms ) + { + booleanQuery.add( parser.parse( previousSearchTerm ), BooleanClause.Occur.MUST ); + } + + query = new LuceneQuery( booleanQuery ); + Filter filter = new QueryWrapperFilter( parser.parse( term ) ); + results = searchAll( query, limits, indexes, filter ); + } results.getRepositories().addAll( this.localIndexedRepositories ); return results; @@ -141,10 +170,10 @@ public class DefaultCrossRepositorySearch } // empty results. - return new SearchResults(); + return new SearchResults(); } - - private SearchResults searchAll( LuceneQuery luceneQuery, SearchResultLimits limits, List indexes ) + + private SearchResults searchAll( LuceneQuery luceneQuery, SearchResultLimits limits, List indexes, Filter filter ) { org.apache.lucene.search.Query specificQuery = luceneQuery.getLuceneQuery(); @@ -175,7 +204,15 @@ public class DefaultCrossRepositorySearch searcher = new MultiSearcher( searchables ); // Perform the search. - Hits hits = searcher.search( specificQuery ); + Hits hits = null; + if( filter != null ) + { + hits = searcher.search( specificQuery, filter ); + } + else + { + hits = searcher.search( specificQuery ); + } int hitCount = hits.length(); diff --git a/archiva-modules/archiva-base/archiva-indexer/src/test/java/org/apache/maven/archiva/indexer/search/DefaultCrossRepositorySearchTest.java b/archiva-modules/archiva-base/archiva-indexer/src/test/java/org/apache/maven/archiva/indexer/search/DefaultCrossRepositorySearchTest.java index a503d6f8b..576b54481 100644 --- a/archiva-modules/archiva-base/archiva-indexer/src/test/java/org/apache/maven/archiva/indexer/search/DefaultCrossRepositorySearchTest.java +++ b/archiva-modules/archiva-base/archiva-indexer/src/test/java/org/apache/maven/archiva/indexer/search/DefaultCrossRepositorySearchTest.java @@ -140,7 +140,7 @@ public class DefaultCrossRepositorySearchTest "org","org2","org3","org4","org5","org6","org7" }; - assertSearchResults( expectedRepos, expectedResults, search, "org" ); + assertSearchResults( expectedRepos, expectedResults, search, "org", null ); } public void testSearchTerm_Junit() @@ -156,7 +156,7 @@ public class DefaultCrossRepositorySearchTest "junit","junit2","junit3" }; - assertSearchResults( expectedRepos, expectedResults, search, "junit" ); + assertSearchResults( expectedRepos, expectedResults, search, "junit", null ); } public void testSearchInvalidTerm() @@ -172,10 +172,49 @@ public class DefaultCrossRepositorySearchTest // Nothing. }; - assertSearchResults( expectedRepos, expectedResults, search, "monosodium" ); + assertSearchResults( expectedRepos, expectedResults, search, "monosodium", null ); } - private void assertSearchResults( String expectedRepos[], String expectedResults[], CrossRepositorySearch search, String term ) + public void testSearchWithinSearchResults() + throws Exception + { + CrossRepositorySearch search = lookupCrossRepositorySearch(); + + String expectedRepos[] = new String[] { + TEST_DEFAULT_REPO_ID + }; + + String expectedResults[] = new String[] { + "org","org2","org3","org4","org5","org6","org7" + }; + + // first search + assertSearchResults( expectedRepos, expectedResults, search, "org", null ); + + List previousSearchTerms = new ArrayList(); + previousSearchTerms.add( "org" ); + String secondSearchExpectedResults[] = new String[] { + "org.apache.maven.archiva.record", "org.apache.maven.archiva.record2", + "org.apache.maven.archiva.record3", "org.apache.maven.archiva.record4", + "org.apache.maven.archiva.record5", "org.apache.maven.archiva.record6", + "org.apache.maven.archiva.record7" + }; + + //second search + assertSearchResults( expectedRepos, secondSearchExpectedResults, search, "org.apache.maven.archiva.record", + previousSearchTerms ); + + previousSearchTerms.add( "org.apache.maven.archiva.record" ); + String thirdSearchExpectedResults[] = new String[] { + "junit", "junit2", "junit3" + }; + + //third search + assertSearchResults( expectedRepos, thirdSearchExpectedResults, search, "junit", previousSearchTerms ); + } + + private void assertSearchResults( String expectedRepos[], String expectedResults[], CrossRepositorySearch search, + String term, List previousSearchTerms ) throws Exception { SearchResultLimits limits = new SearchResultLimits( 0 ); @@ -184,7 +223,15 @@ public class DefaultCrossRepositorySearchTest List selectedRepos = new ArrayList(); selectedRepos.addAll( Arrays.asList( expectedRepos ) ); - SearchResults results = search.searchForTerm( "guest", selectedRepos, term, limits ); + SearchResults results = null; + if( previousSearchTerms == null ) + { + results = search.searchForTerm( "guest", selectedRepos, term, limits ); + } + else + { + results = search.searchForTerm( "guest", selectedRepos, term, limits, previousSearchTerms ); + } assertNotNull( "Search Results should not be null.", results ); assertEquals( "Repository Hits", expectedRepos.length, results.getRepositories().size() ); diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/SearchAction.java b/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/SearchAction.java index d797c072c..92b203c84 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/SearchAction.java +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/SearchAction.java @@ -20,6 +20,7 @@ package org.apache.maven.archiva.web.action; */ import java.net.MalformedURLException; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -83,6 +84,12 @@ public class SearchAction private int currentPage = 0; private int totalPages; + + private boolean searchResultsOnly; + + private String completeQueryString; + + private static final String COMPLETE_QUERY_STRING_SEPARATOR = ";"; public String quickSearch() throws MalformedURLException, RepositoryIndexException, RepositoryIndexSearchException @@ -103,7 +110,15 @@ public class SearchAction return GlobalResults.ACCESS_TO_NO_REPOS; } - results = crossRepoSearch.searchForTerm( getPrincipal(), selectedRepos, q, limits ); + if( searchResultsOnly && !completeQueryString.equals( "" ) ) + { + results = crossRepoSearch.searchForTerm( getPrincipal(), selectedRepos, q, limits, parseCompleteQueryString() ); + } + else + { + completeQueryString = ""; + results = crossRepoSearch.searchForTerm( getPrincipal(), selectedRepos, q, limits ); + } if ( results.isEmpty() ) { @@ -125,7 +140,12 @@ public class SearchAction * to result in a higher score. * - Joakim */ - + + if( !isEqualToPreviousSearchTerm( q ) ) + { + buildCompleteQueryString( q ); + } + return SUCCESS; } @@ -191,6 +211,46 @@ public class SearchAction return Collections.emptyList(); } + private void buildCompleteQueryString( String searchTerm ) + { + if( searchTerm.indexOf( COMPLETE_QUERY_STRING_SEPARATOR ) != -1 ) + { + searchTerm = StringUtils.remove( searchTerm, COMPLETE_QUERY_STRING_SEPARATOR ); + } + + if( completeQueryString == null || "".equals( completeQueryString ) ) + { + completeQueryString = searchTerm; + } + else + { + completeQueryString = completeQueryString + COMPLETE_QUERY_STRING_SEPARATOR + searchTerm; + } + } + + private List parseCompleteQueryString() + { + List parsedCompleteQueryString = new ArrayList(); + String[] parsed = StringUtils.split( completeQueryString, COMPLETE_QUERY_STRING_SEPARATOR ); + CollectionUtils.addAll( parsedCompleteQueryString, parsed ); + + return parsedCompleteQueryString; + } + + private boolean isEqualToPreviousSearchTerm( String searchTerm ) + { + if( !"".equals( completeQueryString ) ) + { + String[] parsed = StringUtils.split( completeQueryString, COMPLETE_QUERY_STRING_SEPARATOR ); + if( StringUtils.equalsIgnoreCase( searchTerm, parsed[ parsed.length - 1 ] ) ) + { + return true; + } + } + + return false; + } + public String getQ() { return q; @@ -230,4 +290,24 @@ public class SearchAction { this.totalPages = totalPages; } + + public boolean isSearchResultsOnly() + { + return searchResultsOnly; + } + + public void setSearchResultsOnly( boolean searchResultsOnly ) + { + this.searchResultsOnly = searchResultsOnly; + } + + public String getCompleteQueryString() + { + return completeQueryString; + } + + public void setCompleteQueryString( String completeQueryString ) + { + this.completeQueryString = completeQueryString; + } } diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/quickSearchForm.jspf b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/quickSearchForm.jspf index 7db37265b..71ef30ae4 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/quickSearchForm.jspf +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/quickSearchForm.jspf @@ -22,6 +22,8 @@