Compare commits

...
Sign in to create a new pull request.

6 commits

20 changed files with 202 additions and 21 deletions

View file

@ -2,7 +2,7 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>fess</artifactId>
<version>14.11.1-SNAPSHOT</version>
<version>14.11.2-SNAPSHOT</version>
<packaging>war</packaging>
<name>Fess</name>
<description>Fess is Full tExt Search System.</description>

View file

@ -83,7 +83,6 @@ import org.lastaflute.web.response.ActionResponse;
import org.lastaflute.web.response.StreamResponse;
import org.lastaflute.web.ruts.process.ActionRuntime;
import org.lastaflute.web.util.LaRequestUtil;
import org.lastaflute.web.util.LaResponseUtil;
import org.lastaflute.web.util.LaServletContextUtil;
import org.opensearch.core.common.text.Text;
import org.opensearch.search.fetch.subphase.highlight.HighlightField;
@ -211,6 +210,9 @@ public class ViewHelper {
textFragmentPrefixLength = fessConfig.getQueryHighlightTextFragmentPrefixLengthAsInteger();
textFragmentSuffixLength = fessConfig.getQueryHighlightTextFragmentSuffixLengthAsInteger();
textFragmentSize = fessConfig.getQueryHighlightTextFragmentSizeAsInteger();
split(fessConfig.getResponseInlineMimetypes(), ",")
.of(stream -> stream.map(String::trim).filter(StringUtil::isNotEmpty).forEach(inlineMimeTypeSet::add));
}
public String getContentTitle(final Map<String, Object> document) {
@ -743,7 +745,16 @@ public class ViewHelper {
}
final String encodedName = URLEncoder.encode(name, Constants.UTF_8).replace("+", "%20");
response.header(CONTENT_DISPOSITION, contentDispositionType + "; filename=\"" + name + "\"; filename*=utf-8''" + encodedName);
final String contentDispositionValue;
if (name.equals(encodedName)) {
contentDispositionValue = contentDispositionType + "; filename=\"" + name + "\"";
} else {
contentDispositionValue = contentDispositionType + "; filename*=utf-8''" + encodedName;
}
if (logger.isDebugEnabled()) {
logger.debug("ResponseHeader: {}: {}", CONTENT_DISPOSITION, contentDispositionValue);
}
response.header(CONTENT_DISPOSITION, contentDispositionValue);
} catch (final Exception e) {
logger.warn("Failed to write a filename: {}", responseData, e);
}
@ -759,7 +770,7 @@ public class ViewHelper {
return;
}
if (mimeType.startsWith("text/")) {
final String charset = LaResponseUtil.getResponse().getCharacterEncoding();
final String charset = responseData.getCharSet();
if (charset != null) {
response.contentType(mimeType + "; charset=" + charset);
return;

View file

@ -673,6 +673,9 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
/** The key of the configuration. e.g. true */
String RESPONSE_HIGHLIGHT_content_title_ENABLED = "response.highlight.content_title.enabled";
/** The key of the configuration. e.g. application/pdf,text/plain */
String RESPONSE_INLINE_MIMETYPES = "response.inline.mimetypes";
/** The key of the configuration. e.g. fess.search */
String INDEX_DOCUMENT_SEARCH_INDEX = "index.document.search.index";
@ -3881,6 +3884,13 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
*/
boolean isResponseHighlightContentTitleEnabled();
/**
* Get the value for the key 'response.inline.mimetypes'. <br>
* The value is, e.g. application/pdf,text/plain <br>
* @return The value of found property. (NotNull: if not found, exception but basically no way)
*/
String getResponseInlineMimetypes();
/**
* Get the value for the key 'index.document.search.index'. <br>
* The value is, e.g. fess.search <br>
@ -8774,6 +8784,10 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
return is(FessConfig.RESPONSE_HIGHLIGHT_content_title_ENABLED);
}
public String getResponseInlineMimetypes() {
return get(FessConfig.RESPONSE_INLINE_MIMETYPES);
}
public String getIndexDocumentSearchIndex() {
return get(FessConfig.INDEX_DOCUMENT_SEARCH_INDEX);
}
@ -10990,6 +11004,7 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
defaultMap.put(FessConfig.RESPONSE_MAX_TITLE_LENGTH, "50");
defaultMap.put(FessConfig.RESPONSE_MAX_SITE_PATH_LENGTH, "100");
defaultMap.put(FessConfig.RESPONSE_HIGHLIGHT_content_title_ENABLED, "true");
defaultMap.put(FessConfig.RESPONSE_INLINE_MIMETYPES, "application/pdf,text/plain");
defaultMap.put(FessConfig.INDEX_DOCUMENT_SEARCH_INDEX, "fess.search");
defaultMap.put(FessConfig.INDEX_DOCUMENT_UPDATE_INDEX, "fess.update");
defaultMap.put(FessConfig.INDEX_DOCUMENT_SUGGEST_INDEX, "fess");

View file

@ -25,7 +25,10 @@ import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser.Operator;
import org.apache.lucene.queryparser.ext.ExtendableQueryParser;
import org.apache.lucene.queryparser.ext.Extensions.Pair;
import org.apache.lucene.search.PhraseQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.codelibs.fess.Constants;
import org.codelibs.fess.exception.QueryParseException;
@ -53,7 +56,7 @@ public class QueryParser {
}
protected org.apache.lucene.queryparser.classic.QueryParser createQueryParser() {
final ExtendableQueryParser parser = new ExtendableQueryParser(defaultField, analyzer);
final LuceneQueryParser parser = new LuceneQueryParser(defaultField, analyzer);
parser.setAllowLeadingWildcard(allowLeadingWildcard);
parser.setDefaultOperator(defaultOperator);
return parser;
@ -109,4 +112,43 @@ public class QueryParser {
public interface FilterChain {
Query parse(final String query);
}
protected static class LuceneQueryParser extends org.apache.lucene.queryparser.classic.QueryParser {
private final String defaultField;
/**
* Creates a new {@link ExtendableQueryParser} instance
*
* @param f the default query field
* @param a the analyzer used to find terms in a query string
*/
public LuceneQueryParser(final String f, final Analyzer a) {
super(f, a);
this.defaultField = f;
}
@Override
protected Query getFieldQuery(final String field, final String queryText, boolean quoted) throws ParseException {
final org.apache.lucene.search.Query query = super.getFieldQuery(field, queryText, quoted);
if (quoted && query instanceof TermQuery termQuery) {
final Pair<String, String> splitField = splitField(defaultField, field);
if (defaultField.equals(splitField.cur)) {
final PhraseQuery.Builder builder = new PhraseQuery.Builder();
builder.add(termQuery.getTerm());
return builder.build();
}
}
return query;
}
protected Pair<String, String> splitField(String defaultField, String field) {
int indexOf = field.indexOf(':');
if (indexOf < 0)
return new Pair<>(field, null);
final String indexField = indexOf == 0 ? defaultField : field.substring(0, indexOf);
final String extensionKey = field.substring(indexOf + 1);
return new Pair<>(indexField, extensionKey);
}
}
}

View file

@ -56,9 +56,6 @@
</postConstruct>
</component>
<component name="viewHelper" class="org.codelibs.fess.helper.ViewHelper">
<postConstruct name="addInlineMimeType">
<arg>"application/pdf"</arg>
</postConstruct>
</component>
<component name="userAgentHelper" class="org.codelibs.fess.helper.UserAgentHelper">
</component>

View file

@ -337,6 +337,7 @@ response.field.site_path=site_path
response.max.title.length=50
response.max.site.path.length=100
response.highlight.content_title.enabled=true
response.inline.mimetypes=application/pdf,text/plain
# document index
index.document.search.index=fess.search

View file

@ -1,4 +1,4 @@
# https://github.com/apache/lucene-solr/blob/master/lucene/analysis/common/src/resources/org/apache/lucene/analysis/snowball/danish_stop.txt
# https://github.com/apache/lucene-solr/blob/master/lucene/analysis/common/src/resources/org/apache/lucene/analysis/snowball/danish_stop.txt
og
i
jeg

View file

@ -1,4 +1,4 @@
# https://github.com/apache/lucene-solr/blob/master/lucene/analysis/common/src/resources/org/apache/lucene/analysis/snowball/german_stop.txt
# https://github.com/apache/lucene-solr/blob/master/lucene/analysis/common/src/resources/org/apache/lucene/analysis/snowball/german_stop.txt
aber
alle
allem

View file

@ -1,4 +1,4 @@
# https://github.com/apache/lucene-solr/blob/master/lucene/analysis/common/src/resources/org/apache/lucene/analysis/snowball/spanish_stop.txt
# https://github.com/apache/lucene-solr/blob/master/lucene/analysis/common/src/resources/org/apache/lucene/analysis/snowball/spanish_stop.txt
de
la
que

View file

@ -1,4 +1,4 @@
# https://github.com/apache/lucene-solr/blob/master/lucene/analysis/common/src/resources/org/apache/lucene/analysis/snowball/finnish_stop.txt
# https://github.com/apache/lucene-solr/blob/master/lucene/analysis/common/src/resources/org/apache/lucene/analysis/snowball/finnish_stop.txt
olla
olen
olet

View file

@ -1,4 +1,4 @@
# https://github.com/apache/lucene-solr/blob/master/lucene/analysis/common/src/resources/org/apache/lucene/analysis/snowball/french_stop.txt
# https://github.com/apache/lucene-solr/blob/master/lucene/analysis/common/src/resources/org/apache/lucene/analysis/snowball/french_stop.txt
au
aux
avec

View file

@ -1,4 +1,4 @@
# https://github.com/apache/lucene-solr/blob/master/lucene/analysis/common/src/resources/org/apache/lucene/analysis/snowball/hungarian_stop.txt
# https://github.com/apache/lucene-solr/blob/master/lucene/analysis/common/src/resources/org/apache/lucene/analysis/snowball/hungarian_stop.txt
a
ahogy
ahol

View file

@ -1,4 +1,4 @@
# https://github.com/apache/lucene-solr/blob/master/lucene/analysis/common/src/resources/org/apache/lucene/analysis/snowball/italian_stop.txt
# https://github.com/apache/lucene-solr/blob/master/lucene/analysis/common/src/resources/org/apache/lucene/analysis/snowball/italian_stop.txt
ad
al
allo

View file

@ -1,4 +1,4 @@
# https://github.com/apache/lucene-solr/blob/master/lucene/analysis/common/src/resources/org/apache/lucene/analysis/snowball/dutch_stop.txt
# https://github.com/apache/lucene-solr/blob/master/lucene/analysis/common/src/resources/org/apache/lucene/analysis/snowball/dutch_stop.txt
de
en
van

View file

@ -1,4 +1,4 @@
# https://github.com/apache/lucene-solr/blob/master/lucene/analysis/common/src/resources/org/apache/lucene/analysis/snowball/norwegian_stop.txt
# https://github.com/apache/lucene-solr/blob/master/lucene/analysis/common/src/resources/org/apache/lucene/analysis/snowball/norwegian_stop.txt
og
i
jeg

View file

@ -1,4 +1,4 @@
# https://github.com/apache/lucene-solr/blob/master/lucene/analysis/common/src/resources/org/apache/lucene/analysis/snowball/portuguese_stop.txt
# https://github.com/apache/lucene-solr/blob/master/lucene/analysis/common/src/resources/org/apache/lucene/analysis/snowball/portuguese_stop.txt
de
a
o

View file

@ -1,4 +1,4 @@
# https://github.com/apache/lucene-solr/blob/master/lucene/analysis/common/src/resources/org/apache/lucene/analysis/snowball/russian_stop.txt
# https://github.com/apache/lucene-solr/blob/master/lucene/analysis/common/src/resources/org/apache/lucene/analysis/snowball/russian_stop.txt
и
в
во

View file

@ -1,4 +1,4 @@
# https://github.com/apache/lucene-solr/blob/master/lucene/analysis/common/src/resources/org/apache/lucene/analysis/snowball/swedish_stop.txt
# https://github.com/apache/lucene-solr/blob/master/lucene/analysis/common/src/resources/org/apache/lucene/analysis/snowball/swedish_stop.txt
och
det
att

View file

@ -234,7 +234,9 @@ public class QueryHelperTest extends UnitFessTestCase {
Map.of("_default", List.of("aaa:bbb")), //
Set.of("aaa:bbb"), //
buildQuery("aaa\\:bbb"));
assertQueryContext(buildQuery("aaa\\:bbb").getQueryBuilder().toString().replaceAll("\\s", ""), buildQuery("\"aaa\\:bbb\""));
assertQueryContext(
"{\"function_score\":{\"query\":{\"bool\":{\"should\":[{\"match_phrase\":{\"title\":{\"query\":\"aaa:bbb\",\"slop\":0,\"zero_terms_query\":\"NONE\",\"boost\":0.5}}},{\"match_phrase\":{\"content\":{\"query\":\"aaa:bbb\",\"slop\":0,\"zero_terms_query\":\"NONE\",\"boost\":0.05}}}],\"adjust_pure_negative\":true,\"boost\":1.0}},\"functions\":[{\"filter\":{\"match_all\":{\"boost\":1.0}},\"field_value_factor\":{\"field\":\"boost\",\"factor\":1.0,\"modifier\":\"none\"}}],\"score_mode\":\"multiply\",\"max_boost\":3.4028235E38,\"boost\":1.0}}",
buildQuery("\"aaa\\:bbb\""));
assertQueryContext(
"{\"function_score\":{\"query\":{\"match_phrase\":{\"title\":{\"query\":\"aaa:bbb\",\"slop\":0,\"zero_terms_query\":\"NONE\",\"boost\":1.0}}},\"functions\":[{\"filter\":{\"match_all\":{\"boost\":1.0}},\"field_value_factor\":{\"field\":\"boost\",\"factor\":1.0,\"modifier\":\"none\"}}],\"score_mode\":\"multiply\",\"max_boost\":3.4028235E38,\"boost\":1.0}}",

View file

@ -0,0 +1,113 @@
/*
* Copyright 2012-2023 CodeLibs Project and the Others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
package org.codelibs.fess.query.parser;
import java.util.List;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.BoostQuery;
import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.PhraseQuery;
import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.WildcardQuery;
import org.codelibs.fess.unit.UnitFessTestCase;
public class QueryParserTest extends UnitFessTestCase {
public void test_LuceneQueryParser() {
QueryParser queryParser = new QueryParser();
Query query = queryParser.createDefaultFilterChain().parse("fess");
assertEquals(TermQuery.class, query.getClass());
assertEquals("_default:fess", ((TermQuery) query).getTerm().toString());
query = queryParser.createDefaultFilterChain().parse("title:fess");
assertEquals(TermQuery.class, query.getClass());
assertEquals("title:fess", ((TermQuery) query).getTerm().toString());
query = queryParser.createDefaultFilterChain().parse("fess*");
assertEquals(PrefixQuery.class, query.getClass());
assertEquals("_default:fess", ((PrefixQuery) query).getPrefix().toString());
query = queryParser.createDefaultFilterChain().parse("fe?s");
assertEquals(WildcardQuery.class, query.getClass());
assertEquals("_default:fe?s", ((WildcardQuery) query).getTerm().toString());
query = queryParser.createDefaultFilterChain().parse("fess~");
assertEquals(FuzzyQuery.class, query.getClass());
assertEquals("_default:fess", ((FuzzyQuery) query).getTerm().toString());
query = queryParser.createDefaultFilterChain().parse("fess^10");
assertEquals(BoostQuery.class, query.getClass());
assertEquals("_default:fess", ((BoostQuery) query).getQuery().toString());
assertEquals(10.0f, ((BoostQuery) query).getBoost());
query = queryParser.createDefaultFilterChain().parse("\"fess\"");
assertEquals(PhraseQuery.class, query.getClass());
assertEquals("_default:fess", ((PhraseQuery) query).getTerms()[0].toString());
query = queryParser.createDefaultFilterChain().parse("\"fess codelibs\"");
assertEquals(PhraseQuery.class, query.getClass());
assertEquals("_default:fess", ((PhraseQuery) query).getTerms()[0].toString());
assertEquals("_default:codelibs", ((PhraseQuery) query).getTerms()[1].toString());
query = queryParser.createDefaultFilterChain().parse("fess codelibs");
assertEquals(BooleanQuery.class, query.getClass());
List<BooleanClause> clauses = ((BooleanQuery) query).clauses();
assertEquals(TermQuery.class, clauses.get(0).getQuery().getClass());
assertEquals("_default:fess", clauses.get(0).getQuery().toString());
assertEquals(Occur.MUST, clauses.get(0).getOccur());
assertEquals(TermQuery.class, clauses.get(1).getQuery().getClass());
assertEquals("_default:codelibs", clauses.get(1).getQuery().toString());
assertEquals(Occur.MUST, clauses.get(1).getOccur());
query = queryParser.createDefaultFilterChain().parse("fess AND codelibs");
assertEquals(BooleanQuery.class, query.getClass());
clauses = ((BooleanQuery) query).clauses();
assertEquals(TermQuery.class, clauses.get(0).getQuery().getClass());
assertEquals("_default:fess", clauses.get(0).getQuery().toString());
assertEquals(Occur.MUST, clauses.get(0).getOccur());
assertEquals(TermQuery.class, clauses.get(1).getQuery().getClass());
assertEquals("_default:codelibs", clauses.get(1).getQuery().toString());
assertEquals(Occur.MUST, clauses.get(1).getOccur());
query = queryParser.createDefaultFilterChain().parse("fess OR codelibs");
assertEquals(BooleanQuery.class, query.getClass());
clauses = ((BooleanQuery) query).clauses();
assertEquals(TermQuery.class, clauses.get(0).getQuery().getClass());
assertEquals("_default:fess", clauses.get(0).getQuery().toString());
assertEquals(Occur.SHOULD, clauses.get(0).getOccur());
assertEquals(TermQuery.class, clauses.get(1).getQuery().getClass());
assertEquals("_default:codelibs", clauses.get(1).getQuery().toString());
assertEquals(Occur.SHOULD, clauses.get(1).getOccur());
query = queryParser.createDefaultFilterChain().parse("\"fess\" codelibs");
assertEquals(BooleanQuery.class, query.getClass());
clauses = ((BooleanQuery) query).clauses();
assertEquals(PhraseQuery.class, clauses.get(0).getQuery().getClass());
assertEquals("_default:fess", ((PhraseQuery) clauses.get(0).getQuery()).getTerms()[0].toString());
assertEquals(Occur.MUST, clauses.get(0).getOccur());
assertEquals(TermQuery.class, clauses.get(1).getQuery().getClass());
assertEquals("_default:codelibs", clauses.get(1).getQuery().toString());
assertEquals(Occur.MUST, clauses.get(1).getOccur());
}
}