Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ under the License.

* Fix for [JSPWIKI-922](https://issues.apache.org/jira/browse/JSPWIKI-922): the `Content-Disposition` header of an attachment download carried a name with non-ASCII characters as a raw byte, which is not valid UTF-8; such names get an ASCII fallback and a `filename*` parameter with the UTF-8 name now ([PR#571](https://github.com/apache/jspwiki/pull/571))
* Fix for [JSPWIKI-501](https://issues.apache.org/jira/browse/JSPWIKI-501): wildcard and prefix searches that contain an underscore find the pages ([PR#543](https://github.com/apache/jspwiki/pull/543))
* Improvement [JSPWIKI-1321](https://issues.apache.org/jira/browse/JSPWIKI-1321): wildcard terms with a * in the middle find the words inside a page name, and the relevance of a search result is at most 100 ([PR#575](https://github.com/apache/jspwiki/pull/575))
* Fix for [JSPWIKI-1138](https://issues.apache.org/jira/browse/JSPWIKI-1138): Install.jsp echoed submitted values without escaping them; they are escaped now ([PR#323](https://github.com/apache/jspwiki/pull/323))
* Fix for [JSPWIKI-1164](https://issues.apache.org/jira/browse/JSPWIKI-1164): a page reached from a search result showed `<` as `&lt;` when the query was highlighted ([PR#538](https://github.com/apache/jspwiki/pull/538))
* Fix for [JSPWIKI-919](https://issues.apache.org/jira/browse/JSPWIKI-919): `VersioningFileProvider#pageExists()` ignored the first version of a page that has no history, so a page dropped into the page directory was reported as missing when the page cache is off ([PR#539](https://github.com/apache/jspwiki/pull/539))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ public Collection< SearchResult > findPages( final String query, final int flags
if( page != null ) {
final PagePermission pp = new PagePermission( page, PagePermission.VIEW_ACTION );
if( mgr.checkPermission( wikiContext.getWikiSession(), pp ) ) {
final int score = ( int ) ( hit.score * 100 );
final int score = hits.scoreDocs[ 0 ].score > 0 ? Math.round( hit.score / hits.scoreDocs[ 0 ].score * 100 ) : 0;

// Get highlighted search contexts
final String text = doc.get( LUCENE_PAGE_CONTENTS );
Expand Down Expand Up @@ -604,6 +604,7 @@ static final class SeparatorAwareQueryParser extends MultiFieldQueryParser {

private static final String NON_SEPARATORS = "[\\p{L}\\p{N}*?]*";
private static final String SEPARATORS = "[^\\p{L}\\p{N}*?]+";
private static final int MAX_WORDS_BETWEEN_PARTS = 1000;

SeparatorAwareQueryParser( final String[] fields, final Analyzer analyzer ) {
super( fields, analyzer );
Expand All @@ -624,6 +625,12 @@ protected Query getPrefixQuery( final String field, final String termStr ) throw

@Override
protected Query getWildcardQuery( final String field, final String termStr ) throws ParseException {
final Query query = separatedWildcardQuery( field, termStr );
final Query inside = LUCENE_PAGE_NAME.equals( field ) ? insideWords( field, termStr ) : null;
return inside == null ? query : either( query, inside );
}

private Query separatedWildcardQuery( final String field, final String termStr ) throws ParseException {
final Query separated = field != null ? separated( field, termStr, false ) : null;
if( separated == null ) {
return super.getWildcardQuery( field, termStr );
Expand All @@ -635,6 +642,30 @@ protected Query getWildcardQuery( final String field, final String termStr ) thr
}
}

/**
* Builds the query for a page name term with a {@code *} between other characters, such as {@code blog*26}. Such a term is also
* looked for inside the words of the name, and its parts are looked for in order in different words, so {@code entry*26*} finds
* {@code blogentry_021126_1}. Returns {@code null} for any other term, which keeps the words it has to start with.
*/
private Query insideWords( final String field, final String termStr ) {
if( !termStr.matches( ".+\\*.+" ) ) {
return null;
}

final String inside = "*" + StringUtils.strip( termStr, "*" ) + "*";
final BooleanQuery.Builder query = new BooleanQuery.Builder()
.add( new WildcardQuery( new Term( field, getAnalyzer().normalize( field, inside ) ) ), BooleanClause.Occur.SHOULD );

final String[] parts = Arrays.stream( termStr.split( "\\*+" ) ).filter( part -> !part.isEmpty() ).toArray( String[]::new );
if( parts.length > 1 && Arrays.stream( parts ).noneMatch( part -> part.matches( ".*" + SEPARATORS + ".*" ) ) ) {
final SpanQuery[] clauses = Arrays.stream( parts )
.map( part -> new SpanMultiTermQueryWrapper<>( new WildcardQuery( new Term( field, getAnalyzer().normalize( field, "*" + part + "*" ) ) ) ) )
.toArray( SpanQuery[]::new );
query.add( new SpanNearQuery( clauses, MAX_WORDS_BETWEEN_PARTS, true ), BooleanClause.Occur.SHOULD );
}
return query.build();
}

/**
* Matches what either query matches. The default query is kept because the analyzer does not always split on a separator, so
* a token like {@code blogentry_021126_1} can hold it and only the default query finds it.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,54 @@ void testWildcardWithoutUnderscoreIsUnchanged() throws Exception {
Assertions.assertEquals( Arrays.asList(), pageNamesFor( "woman*" ) );
}

/** https://issues.apache.org/jira/browse/JSPWIKI-1321 */
@Test
void testWildcardInsideTheWordsOfPageName() throws Exception {
m_engine.saveText( "Weblog_blogentry_021126_1", "first entry" );
m_engine.saveText( "Weblog_blogentry_031226_1", "second entry" );
m_engine.saveText( "Weblog_blogentry_021127_2", "third entry" );
m_engine.saveText( "Man_Page", "a" );
m_engine.saveText( "Human_Page", "b" );
m_engine.saveText( "Woman_Page", "c" );
Awaitility.await( "index" ).until( findsResultsFor( new ArrayList<>(), "name:weblog" ) );
Awaitility.await( "index2" ).until( findsResultsFor( new ArrayList<>(), "name:woman" ) );

final List< String > withTwentySix = Arrays.asList( "Weblog_blogentry_021126_1", "Weblog_blogentry_031226_1" );
Assertions.assertEquals( withTwentySix, pageNamesFor( "name:blog*26" ) );
Assertions.assertEquals( withTwentySix, pageNamesFor( "name:entry*26*" ) );
Assertions.assertEquals( withTwentySix, pageNamesFor( "name:blog*26*" ) );
Assertions.assertEquals( Arrays.asList( "Weblog_blogentry_021127_2" ), pageNamesFor( "name:entry*27*" ) );
Assertions.assertEquals( Arrays.asList(), pageNamesFor( "name:entry*99*" ) );
}

/** https://issues.apache.org/jira/browse/JSPWIKI-1321 */
@Test
void testWildcardAtTheEndOfTermStillStartsAtTheWord() throws Exception {
m_engine.saveText( "Man_Page", "a" );
m_engine.saveText( "Human_Page", "b" );
m_engine.saveText( "Woman_Page", "c" );
Awaitility.await( "index" ).until( findsResultsFor( new ArrayList<>(), "name:woman" ) );

Assertions.assertEquals( Arrays.asList( "Man_Page" ), pageNamesFor( "name:man*" ) );
Assertions.assertEquals( Arrays.asList( "Human_Page", "Man_Page", "Woman_Page" ), pageNamesFor( "name:man*pa*" ) );
}

/** https://issues.apache.org/jira/browse/JSPWIKI-1321 */
@Test
void testRelevanceIsBetweenZeroAndOneHundred() throws Exception {
m_engine.saveText( "Few", "mankind" );
m_engine.saveText( "Many", "mankind mankind mankind mankind mankind mankind mankind mankind" );
m_engine.saveText( "Padded", "mankind and a good many other words to lower the score of this page in the index" );
Awaitility.await( "index" ).until( findsResultsFor( new ArrayList<>(), "Padded" ) );

final Collection< SearchResult > res = new ArrayList<>();
Awaitility.await( "scores" ).until( findsResultsFor( res, "mankind" ) );
final int max = res.stream().mapToInt( SearchResult::getScore ).max().getAsInt();
Assertions.assertEquals( 3, res.size() );
Assertions.assertEquals( 100, max );
Assertions.assertTrue( res.stream().allMatch( r -> r.getScore() >= 0 && r.getScore() <= 100 ) );
}

@Test
public void getPluginList() throws Exception {
DefaultSearchManager defaultSearchManager = new DefaultSearchManager(m_engine, m_engine.getWikiProperties());
Expand Down
Loading