Project

General

Profile

1
package eu.dnetlib.functionality.index.query;
2

    
3
import java.io.ByteArrayInputStream;
4
import java.io.IOException;
5
import java.util.Collection;
6
import java.util.List;
7
import java.util.Map;
8
import java.util.zip.GZIPInputStream;
9

    
10
import com.google.common.base.Predicate;
11
import com.google.common.collect.BiMap;
12
import com.google.common.collect.Iterables;
13
import com.google.common.collect.Lists;
14
import eu.dnetlib.data.provision.index.rmi.BrowsingRow;
15
import eu.dnetlib.data.provision.index.rmi.GroupResult;
16
import eu.dnetlib.functionality.index.utils.IndexFieldUtility;
17
import eu.dnetlib.miscutils.functional.UnaryFunction;
18
import org.apache.commons.io.IOUtils;
19
import org.apache.commons.logging.Log;
20
import org.apache.commons.logging.LogFactory;
21
import org.apache.solr.client.solrj.response.FacetField;
22
import org.apache.solr.client.solrj.response.FacetField.Count;
23
import org.apache.solr.client.solrj.response.QueryResponse;
24
import org.apache.solr.common.SolrDocument;
25
import org.apache.solr.common.SolrDocumentList;
26

    
27
import static eu.dnetlib.miscutils.collections.MappedCollection.listMap;
28

    
29
/**
30
 * The Class SolrResponseParser.
31
 */
32
public class SolrResponseParser extends QueryResponseParser {
33

    
34
	/**
35
	 * logger.
36
	 */
37
	private static final Log log = LogFactory.getLog(SolrResponseParser.class);
38

    
39
	/**
40
	 * Lower level response.
41
	 */
42
	private QueryResponse queryRsp = null;
43

    
44
	/** The wrapper rank. */
45
	protected final UnaryFunction<String, SolrDocument> wrapperRank =
46
			doc -> addRanking(
47
					getSingleField(doc, IndexFieldUtility.RESULT),
48
					getSingleField(doc, IndexFieldUtility.SCORE_FIELD));
49

    
50
	/** The wrapper no rank. */
51
	protected final UnaryFunction<String, SolrDocument> wrapperNoRank =
52
			doc -> wrap(getSingleField(doc, IndexFieldUtility.RESULT));
53

    
54
	/**
55
	 * The Constructor.
56
	 *
57
	 * @param highlightUtils
58
	 *            the highlight utils
59
	 * @param aliases
60
	 *            the aliases
61
	 * @param returnEmptyFields
62
	 *            the return empty fields
63
	 * @param includeRanking
64
	 *            the include ranking
65
	 * @param response
66
	 *            the response
67
	 */
68
	public SolrResponseParser(final UnaryFunction<String, String> highlightUtils, final BiMap<String, String> aliases, final boolean returnEmptyFields,
69
			final boolean includeRanking, final QueryResponse response) {
70
		super(highlightUtils, aliases, returnEmptyFields, includeRanking);
71
		this.queryRsp = response;
72
	}
73

    
74
	/**
75
	 * {@inheritDoc}
76
	 *
77
	 * @see eu.dnetlib.functionality.index.query.QueryResponseParser#getNumFound()
78
	 */
79
	@Override
80
	public long getNumFound() {
81

    
82
		return this.queryRsp.getResults().getNumFound();
83
	}
84

    
85
	/**
86
	 * {@inheritDoc}
87
	 *
88
	 * @see eu.dnetlib.functionality.index.query.QueryResponseParser#getQueryTime()
89
	 */
90
	@Override
91
	public int getQueryTime() {
92
		return queryRsp.getQTime();
93
	}
94

    
95
	/**
96
	 * {@inheritDoc}
97
	 *
98
	 * @see eu.dnetlib.functionality.index.query.QueryResponseParser#getElapsedTime()
99
	 */
100
	@Override
101
	public long getElapsedTime() {
102
		return queryRsp.getElapsedTime();
103
	}
104

    
105
	/**
106
	 * {@inheritDoc}
107
	 *
108
	 * @see eu.dnetlib.functionality.index.query.QueryResponseParser#getStatus()
109
	 */
110
	@Override
111
	public String getStatus() {
112
		return String.valueOf(queryRsp.getStatus());
113
	}
114

    
115
	/**
116
	 * {@inheritDoc}
117
	 *
118
	 * @see eu.dnetlib.functionality.index.query.QueryResponseParser#getCurrentSize()
119
	 */
120
	@Override
121
	public int getCurrentSize() {
122
		return queryRsp.getResults().size();
123
	}
124

    
125
	/**
126
	 * Gets the query response.
127
	 *
128
	 * @return the query response
129
	 */
130
	public QueryResponse getQueryResponse() {
131
		return queryRsp;
132
	}
133

    
134
	/**
135
	 * {@inheritDoc}
136
	 *
137
	 * @see eu.dnetlib.functionality.index.query.QueryResponseParser#getResults()
138
	 */
139
	@Override
140
	public List<String> getResults() {
141
		return asRankedList(queryRsp.getResults());
142
	}
143

    
144
	/**
145
	 * {@inheritDoc}
146
	 *
147
	 * @see eu.dnetlib.functionality.index.query.QueryResponseParser#getNumberOfBrowsingResults()
148
	 */
149
	@Override
150
	public Long getNumberOfBrowsingResults() {
151
		List<FacetField> ffList = queryRsp.getFacetFields();
152
		Long maxCount = 0L;
153

    
154
		if (ffList != null) {
155
			for (FacetField ff : ffList) {
156
				if (ff != null) {
157
					Long countFacets = countFacets(ff.getValues());
158
					if (countFacets > maxCount) {
159
						maxCount = countFacets;
160
					}
161
				}
162
			}
163
		}
164
		return maxCount;
165
	}
166

    
167
	/**
168
	 * {@inheritDoc}
169
	 *
170
	 * @see eu.dnetlib.functionality.index.query.QueryResponseParser#getBrowsingResults()
171
	 */
172
	@Override
173
	public List<BrowsingRow> getBrowsingResults() {
174
		List<BrowsingRow> bresList = Lists.newArrayList();
175
		List<GroupResult> facets = Lists.newArrayList();
176

    
177
		final List<FacetField> ffList = queryRsp.getFacetFields();
178

    
179
		Long numberOfBrowsingResults = getNumberOfBrowsingResults();
180
		for (int i = 0; (ffList != null) && (i < numberOfBrowsingResults); i++) {
181
			for (FacetField ff : ffList) {
182

    
183
				String name = null;
184
				if (aliases != null) {
185
					name = aliases.inverse().get(ff.getName());
186
				}
187

    
188
				// fix #1456
189
				if (name == null) {
190
					name = ff.getName();
191
				}
192

    
193
				final Count facet = getFacet(ff, i);
194

    
195
				if ((facet != null) && (facet.getCount() > 0)) {
196

    
197
					final String value = facet.getName();
198
					final int count = (int) facet.getCount();
199

    
200
					if (returnEmptyFields || !value.isEmpty()) {
201
						facets.add(new GroupResult(name, value, count));
202
					}
203
				}
204
			}
205

    
206
			if (facets.size() > 0) {
207
				bresList.add(new BrowsingRow(Lists.newArrayList(facets)));
208
				facets.clear();
209
			}
210
		}
211
		if (log.isDebugEnabled()) {
212
			log.debug("BrowsingResult size: " + bresList.size());
213
		}
214
		return bresList;
215
	}
216

    
217
	// /////////////// helpers
218

    
219
	/**
220
	 * Gets the facet.
221
	 *
222
	 * @param ff
223
	 *            the ff
224
	 * @param pos
225
	 *            the pos
226
	 * @return the facet
227
	 */
228
	private Count getFacet(final FacetField ff, final int pos) {
229

    
230
		if ((ff.getValues() == null) || (pos >= ff.getValues().size())) return null;
231
		return ff.getValues().get(pos);
232
	}
233

    
234
	/**
235
	 * Given SolrDocumentList, return a List of Strings, representing it.
236
	 *
237
	 * @param documentList
238
	 *            the document list
239
	 * @return the list< string>
240
	 */
241
	private List<String> asRankedList(final SolrDocumentList documentList) {
242

    
243
		UnaryFunction<String, SolrDocument> wrapper = includeRanking ? wrapperRank : wrapperNoRank;
244

    
245
		if (queryRsp.getHighlighting() != null) return listMap(listMap(documentList, doc -> {
246

    
247
			String score = getSingleField(doc, IndexFieldUtility.SCORE_FIELD);
248

    
249
			String hl = getHighlighting(getSingleField(doc, IndexFieldUtility.INDEX_RECORD_ID));
250
			String res = hl != null ? hl : getSingleField(doc, IndexFieldUtility.RESULT);
251

    
252
			return includeRanking ? addRanking(res, score) : wrap(res);
253
		}), highlightUtils);
254

    
255
		return listMap(documentList, wrapper);
256
	}
257

    
258
	/**
259
	 * Converts a String document to
260
	 *
261
	 * <record rank="score"> [document] </record>.
262
	 *
263
	 * @param doc
264
	 *            the doc
265
	 * @param score
266
	 *            the score
267
	 * @return the string
268
	 */
269
	private String addRanking(final String doc, final String score) {
270
		return new String("<record rank=\"" + score + "\">" + doc + "</record>");
271
	}
272

    
273
	/**
274
	 * Wraps the given document as <record> [document] </record>.
275
	 *
276
	 * @param doc
277
	 *            the doc
278
	 * @return the string
279
	 */
280
	private String wrap(final String doc) {
281
		return new String("<record>" + doc + "</record>");
282
	}
283

    
284
	/**
285
	 * Gets the single field.
286
	 *
287
	 * @param doc
288
	 *            the doc
289
	 * @param fieldName
290
	 *            the field name
291
	 * @return the single field
292
	 */
293
	@SuppressWarnings("unchecked")
294
	protected String getSingleField(final SolrDocument doc, final String fieldName) {
295
		Object value = doc.getFieldValue(fieldName);
296
		if (value instanceof Collection) return Iterables.getOnlyElement((Iterable<String>) value);
297
		return String.valueOf(value);
298
	}
299

    
300
	private byte[] base64Decode(final String s) {
301
		return org.apache.solr.common.util.Base64.base64ToByteArray(s);
302
	}
303

    
304
	private String unzip(final byte[] b) {
305
		try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(b)) {
306
			try (GZIPInputStream gzipInputStream = new GZIPInputStream(byteArrayInputStream)) {
307
				return new String(IOUtils.toByteArray(gzipInputStream));
308
			}
309
		} catch(IOException e) {
310
			throw new RuntimeException("Failed to unzip content", e);
311
		}
312
	}
313

    
314
	/**
315
	 * Gets the highlighting.
316
	 *
317
	 * @param docId
318
	 *            the doc id
319
	 * @return the highlighting
320
	 */
321
	private String getHighlighting(final String docId) {
322
		final Map<String, List<String>> highlight = queryRsp.getHighlighting().get(docId);
323

    
324
		String result = new String();
325
		if ((highlight != null) && (highlight.get(IndexFieldUtility.RESULT) != null)) {
326
			for (String s : highlight.get(IndexFieldUtility.RESULT)) {
327
				result = result.concat(s);
328
			}
329
			return result;
330
		}
331
		return null;
332
	}
333

    
334
	/**
335
	 * helper method.
336
	 *
337
	 * @param facets
338
	 *            the list of facets to analyze
339
	 * @return the number of non-empty facets in the list whose count is greater than zero
340
	 */
341
	private Long countFacets(final List<Count> facets) {
342

    
343
		if (facets == null) return 0L;
344

    
345
		return (long) Iterables.size(Iterables.filter(facets, new Predicate<Count>() {
346

    
347
			@Override
348
			public boolean apply(final Count c) {
349
				return (c != null) && (c.getName() != null) && !c.getName().isEmpty() && (c.getCount() > 0);
350
			}
351
		}));
352
	}
353

    
354
	@Override
355
	public long getStart() {
356
		// TODO Auto-generated method stub
357
		return queryRsp.getResults().getStart();
358
	}
359

    
360
}
(5-5/5)