Author: tommaso
Date: Thu Feb 12 15:08:57 2015
New Revision: 1659285
URL: http://svn.apache.org/r1659285
Log:
OAK-2508 - added ACL filtering for spellchecks too
Modified:
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java
jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/AdvancedSolrQueryIndex.java
jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndex.java
jackrabbit/oak/trunk/oak-solr-core/src/main/resources/solr/oak/conf/solrconfig.xml
jackrabbit/oak/trunk/oak-solr-core/src/test/resources/solr/oak/conf/solrconfig.xml
Modified:
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java?rev=1659285&r1=1659284&r2=1659285&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java
(original)
+++
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java
Thu Feb 12 15:08:57 2015
@@ -81,6 +81,7 @@ import org.apache.lucene.analysis.Analyz
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
+import org.apache.lucene.document.Document;
import org.apache.lucene.index.FieldInfo;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.MultiFields;
@@ -106,6 +107,7 @@ import org.apache.lucene.search.Wildcard
import org.apache.lucene.search.spell.SuggestWord;
import org.apache.lucene.search.suggest.Lookup;
import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.Version;
import org.apache.lucene.util.automaton.Automaton;
import org.apache.lucene.util.automaton.CompiledAutomaton;
import org.slf4j.Logger;
@@ -366,19 +368,47 @@ public class LuceneIndex implements Adva
} else if (luceneRequestFacade.getLuceneRequest()
instanceof SpellcheckHelper.SpellcheckQuery) {
SpellcheckHelper.SpellcheckQuery spellcheckQuery =
(SpellcheckHelper.SpellcheckQuery) luceneRequestFacade.getLuceneRequest();
SuggestWord[] suggestWords =
SpellcheckHelper.getSpellcheck(spellcheckQuery);
+
+ // ACL filter spellchecks
Collection<String> suggestedWords = new
ArrayList<String>(suggestWords.length);
- for (SuggestWord suggestWord : suggestWords) {
- suggestedWords.add(suggestWord.string);
+ QueryParser qp = new QueryParser(Version.LUCENE_47,
FieldNames.FULLTEXT, indexNode.getDefinition().getAnalyzer());
+ for (SuggestWord suggestion : suggestWords) {
+ Query query =
qp.createPhraseQuery(FieldNames.FULLTEXT, suggestion.string);
+ TopDocs topDocs = searcher.search(query, 100);
+ if (topDocs.totalHits > 0) {
+ for (ScoreDoc doc : topDocs.scoreDocs) {
+ Document retrievedDoc =
searcher.doc(doc.doc);
+ if
(filter.isAccessible(retrievedDoc.get(FieldNames.PATH))) {
+ suggestedWords.add(suggestion.string);
+ break;
+ }
+ }
+ }
}
+
queue.add(new LuceneResultRow(suggestedWords));
noDocs = true;
} else if (luceneRequestFacade.getLuceneRequest()
instanceof SuggestHelper.SuggestQuery) {
SuggestHelper.SuggestQuery suggestQuery =
(SuggestHelper.SuggestQuery) luceneRequestFacade.getLuceneRequest();
List<Lookup.LookupResult> lookupResults =
SuggestHelper.getSuggestions(suggestQuery);
+
+ // ACL filter suggestions
Collection<String> suggestedWords = new
ArrayList<String>(lookupResults.size());
- for (Lookup.LookupResult suggestWord : lookupResults) {
- suggestedWords.add("{term=" + suggestWord.key +
",weight=" + suggestWord.value + "}");
+ QueryParser qp = new QueryParser(Version.LUCENE_47,
FieldNames.FULLTEXT, indexNode.getDefinition().getAnalyzer());
+ for (Lookup.LookupResult suggestion : lookupResults) {
+ Query query =
qp.createPhraseQuery(FieldNames.FULLTEXT, suggestion.key.toString());
+ TopDocs topDocs = searcher.search(query, 100);
+ if (topDocs.totalHits > 0) {
+ for (ScoreDoc doc : topDocs.scoreDocs) {
+ Document retrievedDoc =
searcher.doc(doc.doc);
+ if
(filter.isAccessible(retrievedDoc.get(FieldNames.PATH))) {
+ suggestedWords.add("{term=" +
suggestion.key + ",weight=" + suggestion.value + "}");
+ break;
+ }
+ }
+ }
}
+
queue.add(new LuceneResultRow(suggestedWords));
noDocs = true;
}
Modified:
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java?rev=1659285&r1=1659284&r2=1659285&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java
(original)
+++
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java
Thu Feb 12 15:08:57 2015
@@ -340,10 +340,24 @@ public class LucenePropertyIndex impleme
} else if (luceneRequestFacade.getLuceneRequest()
instanceof SpellcheckHelper.SpellcheckQuery) {
SpellcheckHelper.SpellcheckQuery spellcheckQuery =
(SpellcheckHelper.SpellcheckQuery) luceneRequestFacade.getLuceneRequest();
SuggestWord[] suggestWords =
SpellcheckHelper.getSpellcheck(spellcheckQuery);
+
+ // ACL filter spellchecks
Collection<String> suggestedWords = new
ArrayList<String>(suggestWords.length);
- for (SuggestWord suggestWord : suggestWords) {
- suggestedWords.add(suggestWord.string);
+ QueryParser qp = new QueryParser(Version.LUCENE_47,
FieldNames.FULLTEXT, indexNode.getDefinition().getAnalyzer());
+ for (SuggestWord suggestion : suggestWords) {
+ Query query =
qp.createPhraseQuery(FieldNames.FULLTEXT, suggestion.string);
+ TopDocs topDocs = searcher.search(query, 100);
+ if (topDocs.totalHits > 0) {
+ for (ScoreDoc doc : topDocs.scoreDocs) {
+ Document retrievedDoc =
searcher.doc(doc.doc);
+ if
(filter.isAccessible(retrievedDoc.get(FieldNames.PATH))) {
+ suggestedWords.add(suggestion.string);
+ break;
+ }
+ }
+ }
}
+
queue.add(new LuceneResultRow(suggestedWords));
noDocs = true;
} else if (luceneRequestFacade.getLuceneRequest()
instanceof SuggestHelper.SuggestQuery) {
Modified:
jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/AdvancedSolrQueryIndex.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/AdvancedSolrQueryIndex.java?rev=1659285&r1=1659284&r2=1659285&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/AdvancedSolrQueryIndex.java
(original)
+++
jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/AdvancedSolrQueryIndex.java
Thu Feb 12 15:08:57 2015
@@ -40,17 +40,13 @@ public class AdvancedSolrQueryIndex exte
private static final Map<String, Long> cache = new WeakHashMap<String,
Long>();
- private final OakSolrConfiguration configuration;
private final SolrServer solrServer;
- private final NodeAggregator aggregator;
private final String name;
public AdvancedSolrQueryIndex(String name, SolrServer solrServer,
OakSolrConfiguration configuration, NodeAggregator aggregator) {
super(name, solrServer, configuration, aggregator);
this.name = name;
- this.configuration = configuration;
this.solrServer = solrServer;
- this.aggregator = aggregator;
}
@Override
@@ -117,11 +113,6 @@ public class AdvancedSolrQueryIndex exte
}
@Override
- public NodeAggregator getNodeAggregator() {
- return aggregator;
- }
-
- @Override
public double getCost(Filter filter, NodeState rootState) {
return super.getCost(filter, rootState);
}
Modified:
jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndex.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndex.java?rev=1659285&r1=1659284&r2=1659285&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndex.java
(original)
+++
jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndex.java
Thu Feb 12 15:08:57 2015
@@ -22,6 +22,7 @@ import java.util.Collections;
import java.util.Deque;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.CheckForNull;
@@ -31,7 +32,6 @@ import com.google.common.collect.Iterabl
import com.google.common.collect.Queues;
import com.google.common.collect.Sets;
import org.apache.jackrabbit.oak.api.PropertyValue;
-import org.apache.jackrabbit.oak.commons.PathUtils;
import org.apache.jackrabbit.oak.plugins.index.aggregate.NodeAggregator;
import
org.apache.jackrabbit.oak.plugins.index.solr.configuration.OakSolrConfiguration;
import org.apache.jackrabbit.oak.query.QueryEngineSettings;
@@ -196,139 +196,170 @@ public class SolrQueryIndex implements F
final int parentDepth = getDepth(parent);
- cursor = new SolrRowCursor(new AbstractIterator<SolrResultRow>() {
- private final Set<String> seenPaths = Sets.newHashSet();
- private final Deque<SolrResultRow> queue =
Queues.newArrayDeque();
- private SolrDocument lastDoc;
- private int offset = 0;
- private boolean noDocs = false;
-
- @Override
- protected SolrResultRow computeNext() {
- if (!queue.isEmpty() || loadDocs()) {
- return queue.remove();
- }
- return endOfData();
+ cursor = new SolrRowCursor(getIterator(filter, parent,
parentDepth), filter.getQueryEngineSettings());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return cursor;
+ }
+
+ private AbstractIterator<SolrResultRow> getIterator(final Filter filter,
final String parent, final int parentDepth) {
+ return new AbstractIterator<SolrResultRow>() {
+ private final Set<String> seenPaths = Sets.newHashSet();
+ private final Deque<SolrResultRow> queue = Queues.newArrayDeque();
+ private SolrDocument lastDoc;
+ private int offset = 0;
+ private boolean noDocs = false;
+
+ @Override
+ protected SolrResultRow computeNext() {
+ if (!queue.isEmpty() || loadDocs()) {
+ return queue.remove();
}
+ return endOfData();
+ }
- private SolrResultRow convertToRow(SolrDocument doc) {
- String path =
String.valueOf(doc.getFieldValue(configuration.getPathField()));
- if (path != null) {
- if ("".equals(path)) {
- path = "/";
- }
- if (!parent.isEmpty()) {
- path = getAncestorPath(path, parentDepth);
- // avoid duplicate entries
- if (seenPaths.contains(path)) {
- return null;
- }
- seenPaths.add(path);
+ private SolrResultRow convertToRow(SolrDocument doc) {
+ String path =
String.valueOf(doc.getFieldValue(configuration.getPathField()));
+ if (path != null) {
+ if ("".equals(path)) {
+ path = "/";
+ }
+ if (!parent.isEmpty()) {
+ path = getAncestorPath(path, parentDepth);
+ // avoid duplicate entries
+ if (seenPaths.contains(path)) {
+ return null;
}
+ seenPaths.add(path);
+ }
- float score = 0f;
- Object scoreObj = doc.get("score");
- if (scoreObj != null) {
- score = (Float) scoreObj;
- }
- return new SolrResultRow(path, score, doc);
+ float score = 0f;
+ Object scoreObj = doc.get("score");
+ if (scoreObj != null) {
+ score = (Float) scoreObj;
}
- return null;
+ return new SolrResultRow(path, score, doc);
}
+ return null;
+ }
- /**
- * Loads the Solr documents in batches
- * @return true if any document is loaded
- */
- private boolean loadDocs() {
+ /**
+ * Loads the Solr documents in batches
+ * @return true if any document is loaded
+ */
+ private boolean loadDocs() {
- if (noDocs) {
- return false;
- }
+ if (noDocs) {
+ return false;
+ }
- SolrDocument lastDocToRecord = null;
+ SolrDocument lastDocToRecord = null;
- try {
- if (log.isDebugEnabled()) {
- log.debug("converting filter {}", filter);
- }
- SolrQuery query = FilterQueryParser.getQuery(filter,
configuration);
- if (lastDoc != null) {
- offset++;
- int newOffset = offset * configuration.getRows();
- query.setParam("start", String.valueOf(newOffset));
- }
- if (log.isDebugEnabled()) {
- log.debug("sending query {}", query);
- }
- QueryResponse queryResponse = solrServer.query(query);
+ try {
+ if (log.isDebugEnabled()) {
+ log.debug("converting filter {}", filter);
+ }
+ SolrQuery query = FilterQueryParser.getQuery(filter,
configuration);
+ if (lastDoc != null) {
+ offset++;
+ int newOffset = offset * configuration.getRows();
+ query.setParam("start", String.valueOf(newOffset));
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("sending query {}", query);
+ }
+ QueryResponse queryResponse = solrServer.query(query);
- SolrDocumentList docs = queryResponse.getResults();
+ if (log.isDebugEnabled()) {
+ log.debug("getting response {}",
queryResponse.getHeader());
+ }
- if (docs != null) {
- onRetrievedDocs(filter, docs);
+ SolrDocumentList docs = queryResponse.getResults();
- if (log.isDebugEnabled()) {
- log.debug("getting docs {}", docs);
- }
+ if (docs != null) {
+ onRetrievedDocs(filter, docs);
- for (SolrDocument doc : docs) {
- SolrResultRow row = convertToRow(doc);
- if (row != null) {
- queue.add(row);
- }
- lastDocToRecord = doc;
+ for (SolrDocument doc : docs) {
+ SolrResultRow row = convertToRow(doc);
+ if (row != null) {
+ queue.add(row);
}
+ lastDocToRecord = doc;
}
+ }
- // handle spellcheck
- SpellCheckResponse spellCheckResponse =
queryResponse.getSpellCheckResponse();
- if (spellCheckResponse != null &&
spellCheckResponse.getSuggestions() != null &&
- spellCheckResponse.getSuggestions().size() >
0) {
- SolrDocument fakeDoc = new SolrDocument();
- for (SpellCheckResponse.Suggestion suggestion :
spellCheckResponse.getSuggestions()) {
- fakeDoc.addField(QueryImpl.REP_SPELLCHECK,
suggestion.getAlternatives());
- }
+ // handle spellcheck
+ SpellCheckResponse spellCheckResponse =
queryResponse.getSpellCheckResponse();
+ if (spellCheckResponse != null &&
spellCheckResponse.getSuggestions() != null &&
+ spellCheckResponse.getSuggestions().size() > 0) {
+ SolrDocument fakeDoc =
getSpellChecks(spellCheckResponse, filter);
+ queue.add(new SolrResultRow("/", 1.0, fakeDoc));
+ noDocs = true;
+ }
+
+ // handle suggest
+ NamedList<Object> response = queryResponse.getResponse();
+ Map suggest = (Map) response.get("suggest");
+ if (suggest != null) {
+ Set<Map.Entry<String, Object>> suggestEntries =
suggest.entrySet();
+ if (!suggestEntries.isEmpty()) {
+ SolrDocument fakeDoc =
getSuggestions(suggestEntries, filter);
queue.add(new SolrResultRow("/", 1.0, fakeDoc));
noDocs = true;
}
-
- // handle suggest
- NamedList<Object> response =
queryResponse.getResponse();
- Map suggest = (Map) response.get("suggest");
- if (suggest != null) {
- Set<Map.Entry<String, Object>> suggestEntries =
suggest.entrySet();
- if (!suggestEntries.isEmpty()) {
- SolrDocument fakeDoc =
getSuggestions(suggestEntries, filter);
- queue.add(new SolrResultRow("/", 1.0,
fakeDoc));
- noDocs = true;
- }
- }
-
- } catch (Exception e) {
- if (log.isWarnEnabled()) {
- log.warn("query via {} failed.", solrServer, e);
- }
- }
- if (lastDocToRecord != null) {
- this.lastDoc = lastDocToRecord;
}
- return !queue.isEmpty();
+ } catch (Exception e) {
+ if (log.isWarnEnabled()) {
+ log.warn("query via {} failed.", solrServer, e);
+ }
+ }
+ if (lastDocToRecord != null) {
+ this.lastDoc = lastDocToRecord;
}
- }, filter.getQueryEngineSettings());
- } catch (Exception e) {
- throw new RuntimeException(e);
+ return !queue.isEmpty();
+ }
+
+ };
+ }
+
+ private SolrDocument getSpellChecks(SpellCheckResponse spellCheckResponse,
Filter filter) throws SolrServerException {
+ SolrDocument fakeDoc = new SolrDocument();
+ List<SpellCheckResponse.Suggestion> suggestions =
spellCheckResponse.getSuggestions();
+ Collection<String> alternatives = new
ArrayList<String>(suggestions.size());
+ for (SpellCheckResponse.Suggestion suggestion : suggestions) {
+ alternatives.addAll(suggestion.getAlternatives());
}
- return cursor;
+
+ // ACL filter spellcheck results
+ for (String alternative : alternatives) {
+ SolrQuery solrQuery = new SolrQuery();
+ solrQuery.setParam("q", alternative);
+ solrQuery.setParam("df", configuration.getCatchAllField());
+ solrQuery.setParam("q.op", "AND");
+ solrQuery.setParam("rows", "100");
+ QueryResponse suggestQueryResponse = solrServer.query(solrQuery);
+ SolrDocumentList results = suggestQueryResponse.getResults();
+ if (results != null && results.getNumFound() > 0) {
+ for (SolrDocument doc : results) {
+ if
(filter.isAccessible(String.valueOf(doc.getFieldValue(configuration.getPathField()))))
{
+ fakeDoc.addField(QueryImpl.REP_SPELLCHECK,
alternative);
+ break;
+ }
+ }
+ }
+ }
+
+ return fakeDoc;
}
private SolrDocument getSuggestions(Set<Map.Entry<String, Object>>
suggestEntries, Filter filter) throws SolrServerException {
Collection<SimpleOrderedMap<Object>> retrievedSuggestions = new
HashSet<SimpleOrderedMap<Object>>();
SolrDocument fakeDoc = new SolrDocument();
- for (Map.Entry<String, Object> suggestor : suggestEntries) {
- SimpleOrderedMap<Object> suggestionResponses = ((SimpleOrderedMap)
suggestor.getValue());
+ for (Map.Entry<String, Object> suggester : suggestEntries) {
+ SimpleOrderedMap<Object> suggestionResponses = ((SimpleOrderedMap)
suggester.getValue());
for (Map.Entry<String, Object> suggestionResponse :
suggestionResponses) {
SimpleOrderedMap<Object> suggestionResults =
((SimpleOrderedMap) suggestionResponse.getValue());
for (Map.Entry<String, Object> suggestionResult :
suggestionResults) {
Modified:
jackrabbit/oak/trunk/oak-solr-core/src/main/resources/solr/oak/conf/solrconfig.xml
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/main/resources/solr/oak/conf/solrconfig.xml?rev=1659285&r1=1659284&r2=1659285&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-solr-core/src/main/resources/solr/oak/conf/solrconfig.xml
(original)
+++
jackrabbit/oak/trunk/oak-solr-core/src/main/resources/solr/oak/conf/solrconfig.xml
Thu Feb 12 15:08:57 2015
@@ -852,9 +852,6 @@
</arr>
-->
<arr name="last-components">
- <str>mlt</str>
- <str>spellcheck</str>
- <str>suggest</str>
</arr>
</requestHandler>
Modified:
jackrabbit/oak/trunk/oak-solr-core/src/test/resources/solr/oak/conf/solrconfig.xml
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/test/resources/solr/oak/conf/solrconfig.xml?rev=1659285&r1=1659284&r2=1659285&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-solr-core/src/test/resources/solr/oak/conf/solrconfig.xml
(original)
+++
jackrabbit/oak/trunk/oak-solr-core/src/test/resources/solr/oak/conf/solrconfig.xml
Thu Feb 12 15:08:57 2015
@@ -808,9 +808,6 @@ Lucene will flush based on whichever lim
</arr>
-->
<arr name="last-components">
- <str>mlt</str>
- <str>spellcheck</str>
- <str>suggest</str>
</arr>
</requestHandler>