Project

General

Profile

1
package eu.dnetlib.index.solr.client;
2

    
3
import java.io.IOException;
4
import java.util.ArrayList;
5
import java.util.HashMap;
6
import java.util.List;
7
import java.util.Map;
8

    
9
import com.google.common.collect.BiMap;
10
import com.google.common.collect.Maps;
11
import eu.dnetlib.clients.index.client.AbstractIndexClient;
12
import eu.dnetlib.clients.index.client.IndexClient;
13
import eu.dnetlib.clients.index.client.IndexClientException;
14
import eu.dnetlib.clients.index.client.response.BrowseEntry;
15
import eu.dnetlib.clients.index.client.response.BrowseValueEntry;
16
import eu.dnetlib.clients.index.client.response.LookupResponse;
17
import eu.dnetlib.clients.index.model.Any.ValueType;
18
import eu.dnetlib.clients.index.query.IndexQueryFactory;
19
import eu.dnetlib.clients.index.query.QueryLanguage;
20
import eu.dnetlib.clients.index.query.QueryResponseFactory;
21
import eu.dnetlib.clients.index.query.QueryResponseParser;
22
import eu.dnetlib.utils.MetadataReference;
23
import eu.dnetlib.index.cql.CqlValueTransformerMap;
24
import eu.dnetlib.index.query.SolrIndexQuery;
25
import eu.dnetlib.index.query.SolrIndexQueryFactory;
26
import eu.dnetlib.index.query.SolrIndexQueryResponse;
27
import eu.dnetlib.index.solr.cql.SolrTypeBasedCqlValueTransformerMapFactory;
28
import eu.dnetlib.rmi.provision.BrowsingRow;
29
import eu.dnetlib.rmi.provision.GroupResult;
30
import org.apache.commons.logging.Log;
31
import org.apache.commons.logging.LogFactory;
32
import org.apache.solr.client.solrj.SolrServerException;
33
import org.apache.solr.client.solrj.impl.CloudSolrClient;
34
import org.apache.solr.client.solrj.request.LukeRequest;
35
import org.apache.solr.client.solrj.response.LukeResponse;
36
import org.apache.solr.client.solrj.response.LukeResponse.FieldInfo;
37
import org.apache.solr.client.solrj.response.LukeResponse.FieldTypeInfo;
38
import org.apache.solr.client.solrj.response.QueryResponse;
39

    
40
/**
41
 * The Class SolrIndexClient.
42
 */
43
public class SolrIndexClient extends AbstractIndexClient implements IndexClient {
44

    
45
	private static final Log log = LogFactory.getLog(SolrIndexClient.class);
46
	/**
47
	 * The server.
48
	 */
49
	private CloudSolrClient client;
50
	private SolrIndexQueryFactory solrIndexQueryFactory;
51
	/**
52
	 * The query response factory.
53
	 */
54
	private QueryResponseFactory<QueryResponse> queryResponseFactory;
55
	private SolrTypeBasedCqlValueTransformerMapFactory tMapFactory;
56

    
57
	/**
58
	 * The Constructor.
59
	 *
60
	 * @param format            the format
61
	 * @param layout            the layout
62
	 * @param interpretation    the interpretation
63
	 * @param serviceProperties the service properties
64
	 * @param tMapFactory
65
	 */
66
	public SolrIndexClient(final String format, final String layout, final String interpretation, final Map<String, String> serviceProperties,
67
			final SolrIndexQueryFactory indexQueryFactory, final QueryResponseFactory<QueryResponse> queryResponseFactory,
68
			final SolrTypeBasedCqlValueTransformerMapFactory tMapFactory) {
69
		super(format, layout, interpretation, serviceProperties);
70

    
71
		log.debug(String.format("Created a new instance of the index of type %s_%s_%s", format, layout, interpretation));
72
		this.solrIndexQueryFactory = indexQueryFactory;
73
		this.queryResponseFactory = queryResponseFactory;
74
		this.tMapFactory = tMapFactory;
75

    
76
	}
77

    
78
	public static Map<String, ValueType> getStringValueTypeMap(final Map<String, FieldInfo> fieldInfos, final Map<String, FieldTypeInfo> fieldTypeInfos) {
79
		final Map<String, ValueType> result = Maps.newHashMap();
80
		for (FieldInfo fieldInfo : fieldInfos.values()) {
81
			FieldTypeInfo fieldTypeInfo = fieldTypeInfos.get(fieldInfo.getType());
82
			final String fieldName = fieldTypeInfo.getName().toLowerCase();
83
			final ValueType fieldType = resolveSolrTypeClassName(fieldName);
84
			result.put(fieldInfo.getName(), fieldType);
85
		}
86
		return result;
87
	}
88

    
89
	private static ValueType resolveSolrTypeClassName(final String solrTypeName) {
90
		if (solrTypeName.contains("LongField")) {
91
			return ValueType.LONG;
92
		} else if (solrTypeName.contains("IntField")) {
93
			return ValueType.LONG;
94
		} else if (solrTypeName.contains("short")) {
95
			return ValueType.LONG;
96
		} else if (solrTypeName.contains("float")) {
97
			return ValueType.DOUBLE;
98
		} else if (solrTypeName.contains("double")) {
99
			return ValueType.DOUBLE;
100
		} else if (solrTypeName.contains("date")) {
101
			return ValueType.DATETIME;
102
		} else {
103
			return ValueType.STRING;
104
		}
105
	}
106

    
107
	/**
108
	 * Do delete.
109
	 *
110
	 * @param query the CQL query
111
	 * @return true, if do delete
112
	 * @throws IndexClientException the index service exception
113
	 */
114
	@Override
115
	public long delete(final String query) throws IndexClientException {
116
		try {
117
			log.debug("delete by query: " + query);
118
			MetadataReference mdRef = new MetadataReference(getFormat(), getLayout(), getInterpretation());
119
			SolrIndexQuery translatedQuery = (SolrIndexQuery) solrIndexQueryFactory.getIndexQuery(QueryLanguage.CQL, query, this, mdRef);
120
			String tquery = translatedQuery.getQuery();
121
			translatedQuery.setQueryLimit(0);
122

    
123
			SolrIndexQueryResponse rsp = new SolrIndexQueryResponse(client.query(translatedQuery));
124
			QueryResponseParser responseParser = queryResponseFactory.getQueryResponseParser(rsp, mdRef);
125
			long total = responseParser.getNumFound();
126
			client.deleteByQuery(tquery);
127
			client.commit();
128
			return total;
129
		} catch (Exception e) {
130
			throw new IndexClientException("unable to run delete by query: " + query, e);
131
		}
132
	}
133

    
134
	/**
135
	 * {@inheritDoc}
136
	 *
137
	 * @throws IndexClientException
138
	 */
139
	@Override
140
	public List<BrowseEntry> browse(final String query, final List<String> browseFields, final int max) throws IndexClientException {
141
		MetadataReference mdRef = new MetadataReference(getFormat(), getLayout(), getInterpretation());
142
		SolrIndexQuery translatedQuery = buildBrowseQuery(query, browseFields, max, mdRef);
143
		return executeBrowseQuery(query, translatedQuery, mdRef, browseFields);
144
	}
145

    
146
	/**
147
	 * {@inheritDoc}
148
	 *
149
	 * @throws IndexClientException
150
	 */
151
	@Override
152
	public List<BrowseEntry> browse(final String query, final List<String> browseFields, final int max, final List<String> filterQuery)
153
			throws IndexClientException {
154
		MetadataReference mdRef = new MetadataReference(getFormat(), getLayout(), getInterpretation());
155
		SolrIndexQuery translatedQuery = buildBrowseQuery(query, browseFields, max, mdRef);
156
		if (filterQuery != null) {
157
			log.debug("Filter Query:");
158
			for (String fq : filterQuery) {
159
				translatedQuery.addFilterQuery(fq);
160
				log.debug("- " + fq);
161
			}
162
		}
163
		return executeBrowseQuery(query, translatedQuery, mdRef, browseFields);
164

    
165
	}
166

    
167
	public SolrIndexQuery buildBrowseQuery(final String query, final List<String> browseFields, final int max, final MetadataReference mdRef)
168
			throws IndexClientException {
169
		log.debug("Browse request for the index collection for query:" + query);
170

    
171
		SolrIndexQuery translatedQuery = (SolrIndexQuery) solrIndexQueryFactory.getIndexQuery(QueryLanguage.CQL, query, this, mdRef);
172
		translatedQuery.setFacet(true);
173
		if (browseFields != null) {
174
			List<String> browsableFields = solrIndexQueryFactory.getBrowsableFields(browseFields, mdRef);
175
			log.debug("Browsing fields:");
176
			for (String field : browsableFields) {
177
				translatedQuery.addFacetField(field);
178
				log.debug("- " + field);
179

    
180
			}
181
			translatedQuery.setFacetLimit(max);
182
			log.debug("max number of browsing field :" + max);
183
		}
184
		return translatedQuery;
185
	}
186

    
187
	private List<BrowseEntry> executeBrowseQuery(final String originalQuery,
188
			final SolrIndexQuery query,
189
			final MetadataReference mdRef,
190
			final List<String> browseFields) throws IndexClientException {
191
		try {
192
			SolrIndexQueryResponse response = new SolrIndexQueryResponse(client.query(query));
193
			QueryResponseParser responseParser = queryResponseFactory.getQueryResponseParser(response, mdRef);
194
			List<BrowsingRow> results = responseParser.getBrowsingResults();
195
			List<BrowseEntry> out = convertBrowseEntry(browseFields, results, responseParser.getAliases());
196
			return out;
197
		} catch (Throwable e) {
198
			throw new IndexClientException("Error on executing a query " + originalQuery, e);
199
		}
200
	}
201

    
202
	/**
203
	 * Creates the connection.
204
	 *
205
	 * @return the string
206
	 * @throws IndexClientException the index client exception
207
	 */
208
	private String getUrl() throws IndexClientException {
209
		String address = serviceProperties.get(ZK_ADDRESS);
210
		if (address == null) { throw new IndexClientException("Unable to load a solr client, missing zk address"); }
211
		return address;
212
	}
213

    
214
	/**
215
	 * Gets the server.
216
	 *
217
	 * @return the server
218
	 * @throws IndexClientException the index client exception
219
	 */
220
	public CloudSolrClient getClient() throws IndexClientException {
221
		if (this.client == null) {
222
			String url = getUrl();
223
			log.debug("create new Client " + url);
224
			client = new CloudSolrClient(url);
225
			client.setDefaultCollection(String.format("%s_%s_%s", getFormat(), getLayout(), getInterpretation()));
226
			try {
227
				client.ping();
228
			} catch (Exception e) {
229
				throw new IndexClientException("oops something went wrong", e);
230
			}
231
		}
232
		return client;
233
	}
234

    
235
	/**
236
	 * Sets the server.
237
	 *
238
	 * @param client the Client
239
	 */
240
	public void setClient(final CloudSolrClient client) {
241
		this.client = client;
242
	}
243

    
244
	@Override
245
	public LookupResponse lookup(final String query, final List<String> filterQuery, final int from, final int to) throws IndexClientException {
246
		log.debug("lookup request for the index collection for query:" + query);
247
		MetadataReference mdRef = new MetadataReference(getFormat(), getLayout(), getInterpretation());
248
		SolrIndexQuery translatedQuery = (SolrIndexQuery) solrIndexQueryFactory.getIndexQuery(QueryLanguage.CQL, query, this, mdRef);
249
		translatedQuery.setQueryOffset(from);
250
		translatedQuery.setQueryLimit(to - from + 1);
251
		if (filterQuery != null) {
252
			for (String fq : filterQuery) {
253
				translatedQuery.addFilterQuery(fq);
254
			}
255
		}
256

    
257
		try {
258
			SolrIndexQueryResponse response = new SolrIndexQueryResponse(client.query(translatedQuery));
259
			QueryResponseParser responseParser = queryResponseFactory.getQueryResponseParser(response, mdRef);
260

    
261
			return new LookupResponse(responseParser);
262
		} catch (Throwable e) {
263
			throw new IndexClientException("Error on executing a query " + query, e);
264
		}
265

    
266
	}
267

    
268
	@Override
269
	public CqlValueTransformerMap getCqlValueTransformerMap(final MetadataReference mdRef) throws IndexClientException {
270
		try {
271
			return this.tMapFactory.getIt(readFieldNamesAndTypes(mdRef.toString()));
272
		} catch (Exception e) {
273
			throw new IndexClientException(e);
274

    
275
		}
276
	}
277

    
278
	@Override
279
	public IndexQueryFactory getIndexQueryFactory() {
280
		return solrIndexQueryFactory;
281
	}
282

    
283
	@Override
284
	public void stop() throws IndexClientException {
285
		try {
286
			log.debug("shutdown client: " + serviceProperties.get(ZK_ADDRESS));
287
			client.close();
288
		} catch (Throwable e) {
289
			throw new IndexClientException(e);
290
		}
291
	}
292

    
293
	private List<BrowseEntry> convertBrowseEntry(final List<String> browseFields, final List<BrowsingRow> results, final BiMap<String, String> aliases) {
294

    
295
		Map<String, BrowseEntry> mapResult = new HashMap<>();
296
		for (BrowsingRow row : results) {
297
			for (GroupResult groupResult : row.getGroupResult()) {
298
				String name = groupResult.getName();
299
				List<BrowseValueEntry> valuesEntry;
300
				BrowseEntry entry;
301
				if (mapResult.containsKey(name)) {
302
					entry = mapResult.get(name);
303
					valuesEntry = entry.getValues();
304
					if (valuesEntry == null) {
305
						valuesEntry = new ArrayList<>();
306
						entry.setValues(valuesEntry);
307
					}
308

    
309
				} else {
310
					entry = new BrowseEntry();
311
					entry.setField(name);
312
					entry.setLabel(name);
313
					valuesEntry = new ArrayList<>();
314
					entry.setValues(valuesEntry);
315
					mapResult.put(name, entry);
316
				}
317
				String value = groupResult.getValue();
318
				int count = groupResult.getCount();
319
				BrowseValueEntry entryValue = new BrowseValueEntry(value, count);
320
				valuesEntry.add(entryValue);
321
			}
322
		}
323
		List<BrowseEntry> out = new ArrayList<>();
324
		for (String b : browseFields) {
325
			String inverse = null;
326
			if (aliases != null) {
327
				inverse = aliases.get(b) != null ? aliases.get(b) : aliases.inverse().get(b);
328
			}
329
			if (mapResult.containsKey(b)) {
330
				out.add(mapResult.get(b));
331
			} else if (mapResult.containsKey(inverse) == true) {
332
				BrowseEntry data = mapResult.get(inverse);
333
				data.setField(b);
334
				out.add(data);
335
			}
336
		}
337
		return out;
338
	}
339

    
340
	private Map<String, ValueType> readFieldNamesAndTypes(final String coreName) throws SolrServerException, IOException, IndexClientException {
341
		// final SolrServer server = cloudServer.getSolrServer(coreName);
342
		final LukeRequest request = new LukeRequest();
343
		request.setShowSchema(true);
344

    
345
		// cloudServer.setDefaultCollection(coreName);
346
		request.setNumTerms(0);
347
		final LukeResponse response = request.process(getClient());
348
		final Map<String, FieldInfo> fieldInfos = response.getFieldInfo();
349
		final Map<String, LukeResponse.FieldTypeInfo> fieldTypeInfos = response.getFieldTypeInfo();
350
		return getStringValueTypeMap(fieldInfos, fieldTypeInfos);
351
	}
352

    
353
}
(1-1/2)