001
014
015 package com.liferay.portal.kernel.search;
016
017 import com.liferay.portal.kernel.dao.orm.QueryUtil;
018 import com.liferay.portal.kernel.dao.search.SearchPaginationUtil;
019 import com.liferay.portal.kernel.util.ArrayUtil;
020 import com.liferay.portal.kernel.util.GetterUtil;
021 import com.liferay.portal.kernel.util.PropsKeys;
022 import com.liferay.portal.kernel.util.PropsUtil;
023 import com.liferay.portal.kernel.util.Time;
024
025 import java.util.ArrayList;
026 import java.util.List;
027
028
031 public abstract class BaseSearchResultPermissionFilter
032 implements SearchResultPermissionFilter {
033
034 @Override
035 public Hits search(SearchContext searchContext) throws SearchException {
036 int end = searchContext.getEnd();
037 int start = searchContext.getStart();
038
039 if ((end == QueryUtil.ALL_POS) && (start == QueryUtil.ALL_POS)) {
040 Hits hits = getHits(searchContext);
041
042 if (!isGroupAdmin(searchContext)) {
043 filterHits(hits, searchContext);
044 }
045
046 return hits;
047 }
048
049 if ((start < 0) || (start > end)) {
050 return new HitsImpl();
051 }
052
053 if (isGroupAdmin(searchContext)) {
054 return getHits(searchContext);
055 }
056
057 double amplificationFactor = 1.0;
058 int excludedDocsSize = 0;
059 int hitsSize = 0;
060 int offset = 0;
061 long startTime = 0;
062
063 List<Document> documents = new ArrayList<Document>();
064 List<Float> scores = new ArrayList<Float>();
065
066 while (true) {
067 int count = end - documents.size();
068
069 int amplifiedCount = (int)Math.ceil(count * amplificationFactor);
070
071 int amplifiedEnd = offset + amplifiedCount;
072
073 searchContext.setEnd(amplifiedEnd);
074 searchContext.setStart(offset);
075
076 Hits hits = getHits(searchContext);
077
078 if (startTime == 0) {
079 hitsSize = hits.getLength();
080 startTime = hits.getStart();
081 }
082
083 Document[] oldDocs = hits.getDocs();
084
085 filterHits(hits, searchContext);
086
087 Document[] newDocs = hits.getDocs();
088
089 excludedDocsSize += oldDocs.length - newDocs.length;
090
091 collectHits(hits, documents, scores, count);
092
093 if ((newDocs.length >= count) ||
094 (oldDocs.length < amplifiedCount) ||
095 (amplifiedEnd >= hitsSize)) {
096
097 updateHits(
098 hits, documents, scores, start, end,
099 hitsSize - excludedDocsSize, startTime);
100
101 return hits;
102 }
103
104 offset = amplifiedEnd;
105
106 amplificationFactor = _getAmplificationFactor(
107 documents.size(), offset);
108 }
109 }
110
111 protected void collectHits(
112 Hits hits, List<Document> documents, List<Float> scores, int count) {
113
114 Document[] docs = hits.getDocs();
115
116 if (docs.length < count) {
117 count = docs.length;
118 }
119
120 for (int i = 0; i < count; i++) {
121 documents.add(docs[i]);
122
123 scores.add(hits.score(i));
124 }
125 }
126
127 protected abstract void filterHits(Hits hits, SearchContext searchContext);
128
129 protected abstract Hits getHits(SearchContext searchContext)
130 throws SearchException;
131
132 protected abstract boolean isGroupAdmin(SearchContext searchContext);
133
134 protected void updateHits(
135 Hits hits, List<Document> documents, List<Float> scores, int start,
136 int end, int size, long startTime) {
137
138 int[] startAndEnd = SearchPaginationUtil.calculateStartAndEnd(
139 start, end, documents.size());
140
141 start = startAndEnd[0];
142 end = startAndEnd[1];
143
144 documents = documents.subList(start, end);
145 scores = scores.subList(start, end);
146
147 hits.setDocs(documents.toArray(new Document[documents.size()]));
148 hits.setScores(ArrayUtil.toFloatArray(scores));
149 hits.setLength(size);
150 hits.setSearchTime(
151 (float)(System.currentTimeMillis() - startTime) / Time.SECOND);
152 }
153
154 private double _getAmplificationFactor(double totalViewable, double total) {
155 if (totalViewable == 0) {
156 return _INDEX_PERMISSION_FILTER_SEARCH_AMPLIFICATION_FACTOR;
157 }
158
159 return Math.min(
160 1.0 / (totalViewable / total),
161 _INDEX_PERMISSION_FILTER_SEARCH_AMPLIFICATION_FACTOR);
162 }
163
164 private static final double
165 _INDEX_PERMISSION_FILTER_SEARCH_AMPLIFICATION_FACTOR =
166 GetterUtil.getDouble(
167 PropsUtil.get(
168 PropsKeys.
169 INDEX_PERMISSION_FILTER_SEARCH_AMPLIFICATION_FACTOR));
170
171 }