Project

General

Profile

1
package eu.dnetlib.data.search.app;
2

    
3
import eu.dnetlib.api.data.IndexService;
4
import eu.dnetlib.api.data.IndexServiceException;
5
import eu.dnetlib.api.data.SearchService;
6
import eu.dnetlib.api.data.SearchServiceException;
7
import eu.dnetlib.api.enabling.ISLookUpService;
8
import eu.dnetlib.common.rmi.UnimplementedException;
9
import eu.dnetlib.data.search.app.plan.FieldRewriteRule;
10
import eu.dnetlib.data.search.app.plan.QueryRewriteRule;
11
import eu.dnetlib.data.search.solr.SolrResultSet;
12
import eu.dnetlib.data.search.transform.Transformer;
13
import eu.dnetlib.data.search.transform.config.SearchRegistry;
14
import eu.dnetlib.data.search.transform.formatter.Formatter;
15
import eu.dnetlib.domain.ActionType;
16
import eu.dnetlib.domain.EPR;
17
import eu.dnetlib.domain.ResourceType;
18
import eu.dnetlib.domain.data.FormattedSearchResult;
19
import eu.dnetlib.domain.data.SearchResult;
20
import eu.dnetlib.domain.data.SuggestiveResult;
21
import eu.dnetlib.domain.enabling.Notification;
22
import gr.uoa.di.driver.app.DriverServiceImpl;
23
import gr.uoa.di.driver.enabling.issn.NotificationListener;
24
import gr.uoa.di.driver.enabling.resultset.ResultSet;
25
import gr.uoa.di.driver.enabling.resultset.ResultSetFactory;
26
import gr.uoa.di.driver.util.ServiceLocator;
27
import org.apache.log4j.Logger;
28
import org.apache.solr.client.solrj.SolrServerException;
29
import org.w3c.dom.Document;
30
import org.w3c.dom.Node;
31
import org.xml.sax.InputSource;
32

    
33
import javax.xml.parsers.DocumentBuilder;
34
import javax.xml.parsers.DocumentBuilderFactory;
35
import javax.xml.xpath.XPath;
36
import javax.xml.xpath.XPathConstants;
37
import javax.xml.xpath.XPathExpression;
38
import javax.xml.xpath.XPathFactory;
39
import java.io.OutputStream;
40
import java.io.StringReader;
41
import java.util.*;
42

    
43
//import eu.dnetlib.utils.cql.CqlException;
44

    
45
public class SearchServiceImpl extends DriverServiceImpl
46
        implements SearchService {
47

    
48
    private static Logger logger = Logger.getLogger(SearchServiceImpl.class);
49
    //@Deprecated
50
    //private static Logger tlogger = Logger.getLogger("eu.dnetlib.data.search.app.Timer");
51

    
52
    private String mdFormat = "DMF";
53
    private String indexLayout = "index";
54

    
55
    private ServiceLocator<IndexService> indexLocator = null;
56
    private ServiceLocator<ISLookUpService> lookUpServiceServiceLocator = null;
57
    private ResultSetFactory rsFactory = null;
58

    
59
    private SearchRegistry transformerFactory = null;
60

    
61
    private List<QueryRewriteRule> queryRules = null;
62
    private List<String> fieldQueryRules = null;
63

    
64
    private Map<String, FieldRewriteRule> fieldRules = null;
65
    private boolean enableBrowseCache = false;
66

    
67
    private SearchServiceBlackboardHandler blackboardNotificationHandler = null;
68

    
69
    //private CQLParser cqlParser = null;
70
    @Override
71
    public void init() {
72
        super.init();
73

    
74
        String serviceId = this.getServiceEPR().getParameter("serviceId");
75

    
76
        this.subscribe(
77
                ActionType.UPDATE,
78
                ResourceType.ANY.SEARCHSERVICERESOURCETYPE,
79
                serviceId,
80
                "RESOURCE_PROFILE/BODY/BLACKBOARD/LAST_REQUEST",
81
                new NotificationListener() {
82

    
83
                    @Override
84
                    public void processNotification(Notification notification) {
85
                        blackboardNotificationHandler.notified(
86
                                notification.getSubscriptionId(),
87
                                notification.getTopic(),
88
                                notification.getIsId(),
89
                                notification.getMessage());
90
                    }
91
                });
92

    
93
        try {
94
            String searchProfile = lookUpServiceServiceLocator.getService().getResourceProfile(serviceId);
95

    
96
            if (searchProfile != null) {
97
                DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
98
                dbf.setNamespaceAware(true);
99
                DocumentBuilder db = dbf.newDocumentBuilder();
100
                Document doc = db.parse(new InputSource(new StringReader(searchProfile)));
101

    
102

    
103
                XPathFactory factory = XPathFactory.newInstance();
104
                XPath xpath = factory.newXPath();
105

    
106
                XPathExpression searchMdFormatExpression = xpath.compile("//SERVICE_PROPERTIES/PROPERTY[@key='mdformat']");
107
                Node node = (Node) searchMdFormatExpression.evaluate(doc,XPathConstants.NODE);
108

    
109
                if (node != null){
110
                    String profileMdFormat = node.getAttributes().getNamedItem("value").getTextContent();
111
                    if (profileMdFormat != null) {
112
                        //logger.debug("mdformat in properties " + mdFormat );
113
                        logger.info("Setting mdformat to '" + profileMdFormat + "'");
114
                        mdFormat = profileMdFormat;
115
                    }
116
                }
117
            }
118

    
119
        } catch (Exception e) {
120
            logger.error("Fail to load search service profile with id " + serviceId + " from IS.", e);
121
        }
122

    
123
    }
124

    
125
    @Override
126
    public SuggestiveResult suggestiveSearch(String query) throws SearchServiceException {
127
        throw new UnimplementedException();
128
    }
129

    
130
    @Override
131
    @Deprecated
132
    public SearchResult search(String text, String transformer, String locale, int page, int size) throws SearchServiceException {
133
        return searchNrefine(text, transformer, null, locale, page, size, null);
134
    }
135

    
136
    @Override
137
    @Deprecated
138
    public SearchResult refine(String text, String transformer, String locale, Collection<String> fields) throws SearchServiceException {
139
        return searchNrefine(text, null, transformer, locale, 1, -1, fields);
140
    }
141

    
142
    @Override
143
    @Deprecated
144
    public SearchResult searchNrefine(String text, String searchTransformer, String browseTransformer,
145
                                      String locale, int page, int size, Collection<String> fields) throws SearchServiceException {
146

    
147
        //logger.info("deprecated searchNrefine > from: " + page + " to:" + size);
148
        //TODO check locale
149
        //logger.debug("Search transformer " + searchTransformer);
150
        Transformer sTransformer = transformerFactory.getTransformer(searchTransformer, Locale.getDefault());
151
        Transformer oldRefineTransformer = transformerFactory.getTransformer("results_openaire_browse", Locale.getDefault());
152

    
153
        //logger.debug("Refine transformer " + browseTransformer);
154
        //Transformer rTranformer = transformerFactory.getTransformer(refineTransformer, Locale.getDefault());
155

    
156
        List<String> refineFields = null;
157
        if (fields!=null) {
158
            refineFields = new ArrayList<String>(fields);
159
        }
160

    
161
        return newSearch(text, locale, refineFields, new ArrayList<String>(), page, size, "", sTransformer, oldRefineTransformer, true);
162
    }
163

    
164
    @Override
165
    public FormattedSearchResult search(String queryText, String transformerName, String format, String locale, int page, int size)
166
            throws SearchServiceException {
167
        return searchNrefine(queryText, transformerName, null, format, locale, page, size, null);
168
    }
169

    
170
    @Override
171
    public FormattedSearchResult refine(String queryText, String refineTransformer, String format, String locale, Collection<String> fields) throws SearchServiceException {
172
        return searchNrefine(queryText, null, refineTransformer, format, locale, 0, -1, fields);
173
    }
174

    
175
    @Override
176
    public FormattedSearchResult searchNrefine(String queryText,
177
                                               String searchTransformer, String refineTransformer, String format,
178
                                               String locale, int page, int size, Collection<String> fields)  throws SearchServiceException {
179

    
180

    
181
        //logger.info("searchNrefine > from: " + page + " to:" + size);
182
        //TODO check locale
183
        FormattedSearchResult formattedSearchResult = null;
184

    
185
        //logger.debug("Search transformer " + searchTransformer);
186
        Transformer sTransformer = transformerFactory.getTransformer(searchTransformer, Locale.getDefault());
187
        Transformer oldRefineTransformer = transformerFactory.getTransformer("results_openaire_browse", Locale.getDefault());
188

    
189
        //logger.debug("Refine transformer " + refineTransformer);
190
        //Transformer rTranformer = transformerFactory.getTransformer(refineTransformer, Locale.getDefault());
191

    
192
        List<String> refineFields = null;
193
        if (fields!=null) {
194
            refineFields = new ArrayList<String>(fields);
195
        }
196
        SearchResult searchResult = newSearch(queryText, locale, refineFields, new ArrayList<String>(), page, size, format, sTransformer, oldRefineTransformer, true);
197

    
198
        Formatter formatter = transformerFactory.getFormatter(format); // formatter cannot be returned as null
199
        try {
200
            formattedSearchResult = new FormattedSearchResult(formatter.format(searchResult), searchResult.getTotal());
201

    
202
        } catch (Exception e) {
203
            logger.error("Error formating search results.", e);
204
        }
205

    
206
        return formattedSearchResult;
207
    }
208

    
209
    public SearchResult newSearch (String text, String locale, List<String> refinefields, List<String> fieldQueries,
210
                                   int from, int to, String format, Transformer transformer, Transformer oldRefineTransformer,
211
                                   boolean oldPaging) throws SearchServiceException {
212
        logger.info("newSearch > from: " + from + " to:" + to);
213
        long startTime = System.nanoTime();
214

    
215
        IndexService index = getIndexLocator().getService();
216

    
217
        EPR epr = null;
218
        ResultSet<String> rs = null;
219

    
220
        List<String> browseResults = null;
221
        List<String> searchResults = null;
222

    
223
        String query = rewrite(text);
224
        enhanceFieldQueries(fieldQueries);
225
        logger.info("Performing query " + query + "' and fields " + fieldQueries + " and refine " + refinefields);
226

    
227
        try {
228
            //TODO see parser and maybe delete!
229
            //query = new CQLParser().parse(query).toCQL();
230
            String eprQuery = createEprQuery(query, refinefields, fieldQueries);
231

    
232
            epr = index.getBrowsingStatistics(eprQuery, "all", mdFormat, indexLayout);
233

    
234
            if (epr == null) {
235
                throw new SearchServiceException("Something really strange happened there! Index returned null result set id.");
236
            }
237

    
238
            //get the locale TODO do we need this?
239
            //String correctLocale = getCorrectLocale(locale);
240
            //StringTokenizer tokenizer = new StringTokenizer(correctLocale, "_");
241
            //Locale requestLocale = new Locale(tokenizer.nextToken(), tokenizer.nextToken());
242

    
243
            rs = rsFactory.createResultSet(epr);
244

    
245
            Map<String, List<String>> list = null;
246
            if (oldPaging) {
247
                list = ((SolrResultSet)rs).newGet(from-1, to, format, transformer, oldRefineTransformer);
248

    
249
            } else {
250
                list = ((SolrResultSet)rs).newGet(from, to, format, transformer, oldRefineTransformer);
251
            }
252

    
253

    
254
            searchResults = list.get("search");
255
            browseResults = list.get("refine");
256

    
257
        } catch (IndexServiceException ise) {
258
            logger.error("Error getting refine results.", ise);
259
            throw new SearchServiceException("Error getting refine results.", ise);
260

    
261
        }
262

    
263
        long estimatedTime = System.nanoTime() - startTime;
264
        logger.debug("Search time " + estimatedTime/1000000 +  " milliseconds for query " + query +
265
                " and fields " + fieldQueries + " and refine " + refinefields + " from: "+ from + " and size " + to);
266

    
267
        //logger.info("Returned results for NEW search query '" + query + "' and fields " + fieldQueries + " and refine " + refinefields);;
268
        rs.close();
269
        return new SearchResult(query, Locale.getDefault().toString(), rs.size(), from, to, searchResults, browseResults, refinefields);
270
    }
271
    public void cursorSearch(String text, List<String> refinefields, List<String> fieldQueries,
272
                                       String format, Transformer transformer, OutputStream os) throws SearchServiceException {
273

    
274
        long startTime = System.nanoTime();
275

    
276
        IndexService index = getIndexLocator().getService();
277

    
278
        EPR epr = null;
279
        ResultSet<String> rs = null;
280

    
281
        String query = rewrite(text);
282
        enhanceFieldQueries(fieldQueries);
283
        logger.info("Performing cursor query " + query + "' and fields " + fieldQueries + " and refine " + refinefields);
284
        logger.debug("Performing cursor query " + query + "' and fields " + fieldQueries + " and refine " + refinefields);
285

    
286

    
287
        try {
288
            String eprQuery = createEprQuery(query, refinefields, fieldQueries);
289
            epr = index.getBrowsingStatistics(eprQuery, "all", mdFormat, indexLayout);
290

    
291
            if (epr == null) {
292
                throw new SearchServiceException("Something really strange happened there! Index returned null result set id.");
293
            }
294

    
295
            rs = rsFactory.createResultSet(epr);
296

    
297
            ((SolrResultSet)rs).cursorGet(transformer,os);
298

    
299
        } catch (IndexServiceException ise) {
300
            logger.error("Error getting cursor results.", ise);
301
            throw new SearchServiceException("Error getting cursor results.", ise);
302

    
303
        } catch (SolrServerException sse) {
304
            logger.error("Error getting cursor results.", sse);
305
            throw new SearchServiceException("Error getting cursor results.", sse);
306
        }
307

    
308
        long estimatedTime = System.nanoTime() - startTime;
309
        logger.debug("Cursor search time " + estimatedTime/1000000 +  " milliseconds for query " + query +
310
                " and fields " + fieldQueries + " and refine " + refinefields);
311

    
312
        rs.close();
313
    }
314

    
315

    
316
    private String rewrite(String query) {
317
        if (queryRules != null) {
318
            for (QueryRewriteRule queryRule: queryRules) {
319
                if (logger.isDebugEnabled()) {
320
                    logger.debug("Apply rule " + query);
321
                }
322
                query = queryRule.apply(query);
323
                if (logger.isDebugEnabled()) {
324
                    logger.debug("Rewritten query is " + query);
325
                }
326
            }
327
        }
328
        return query;
329
    }
330

    
331
    private void enhanceFieldQueries(List<String> fieldQueries) {
332
        if (fieldQueries != null && fieldQueryRules != null && !fieldQueryRules.isEmpty()) {
333
            fieldQueries.addAll(fieldQueryRules);
334
        }
335
    }
336

    
337
    public void setFieldRules(Collection<FieldRewriteRule> fieldRules) {
338
        this.fieldRules = new HashMap<String, FieldRewriteRule>();
339
        for (FieldRewriteRule rule : fieldRules) {
340
            String key = rule.getFieldName();
341
            if (this.fieldRules.containsKey(key)) {
342
                logger.warn("Multiple rules for field " + key);
343
                logger.warn("Keeping last rule " + rule.getName());
344
            }
345
            this.fieldRules.put(key, rule);
346
        }
347
    }
348

    
349
    public static String createEprQuery(String query, List<String> refineFields, List<String> fieldQueries) {
350
        StringBuffer queryBuffer = new StringBuffer();
351
        queryBuffer.append("query=");
352

    
353
        StringBuffer facetsBuffer = new StringBuffer();
354
        facetsBuffer.append("&groupby=");
355

    
356
        StringBuffer fqBuffer = new StringBuffer();
357
        fqBuffer.append("&fq=");
358

    
359
        if (query != null) { //TODO consider exception?
360
            queryBuffer.append(query);
361
        }
362

    
363
        if(refineFields != null) {
364
            for (Iterator<String> iterator = refineFields.iterator(); iterator.hasNext(); ) {
365
                facetsBuffer.append(iterator.next());
366
                if (iterator.hasNext()) {
367
                    facetsBuffer.append(",");
368
                }
369
            }
370
        }
371

    
372
        if(fieldQueries != null) {
373
            for (Iterator<String> iterator = fieldQueries.iterator(); iterator.hasNext(); ) {
374
                fqBuffer.append(iterator.next());
375
                if (iterator.hasNext()) {
376
                    fqBuffer.append(",");
377
                }
378
            }
379
        }
380

    
381
        return queryBuffer.append(facetsBuffer.toString()).append(fqBuffer.toString()).toString();
382
    }
383

    
384

    
385
    //TODO: I wish to remove this. This was only made (quick and dirty - only the enhanceFieldQueries(fieldQueries) is missing
386
    //from newSearch() after a last time request for the portal to show all the publications and the deletedbyinference ones.
387
    //I did not want to pass a parameter since I do not know if we are going to keep it. This is for a tech meeting showcase.
388
    //If we want to keep this I need to redesign.
389

    
390
    public SearchResult newSearchWithoutFieldQueries (String text, String locale, List<String> refinefields, List<String> fieldQueries,
391
                                   int from, int to, String format, Transformer transformer, Transformer oldRefineTransformer,
392
                                   boolean oldPaging) throws SearchServiceException {
393
        logger.info("non filtered search for...  > from: " + from + " to:" + to);
394
        long startTime = System.nanoTime();
395

    
396
        IndexService index = getIndexLocator().getService();
397

    
398
        EPR epr = null;
399
        ResultSet<String> rs = null;
400

    
401
        List<String> browseResults = null;
402
        List<String> searchResults = null;
403

    
404
        String query = rewrite(text);
405
        logger.info("Performing query " + query + "' and fields " + fieldQueries + " and refine " + refinefields);
406

    
407
        try {
408
            //TODO see parser and maybe delete!
409
            //query = new CQLParser().parse(query).toCQL();
410
            String eprQuery = createEprQuery(query, refinefields, fieldQueries);
411

    
412
            epr = index.getBrowsingStatistics(eprQuery, "all", mdFormat, indexLayout);
413

    
414
            if (epr == null) {
415
                throw new SearchServiceException("Something really strange happened there! Index returned null result set id.");
416
            }
417

    
418
            //get the locale TODO do we need this?
419
            //String correctLocale = getCorrectLocale(locale);
420
            //StringTokenizer tokenizer = new StringTokenizer(correctLocale, "_");
421
            //Locale requestLocale = new Locale(tokenizer.nextToken(), tokenizer.nextToken());
422

    
423
            rs = rsFactory.createResultSet(epr);
424

    
425
            Map<String, List<String>> list = null;
426
            if (oldPaging) {
427
                list = ((SolrResultSet)rs).newGet(from-1, to, format, transformer, oldRefineTransformer);
428

    
429
            } else {
430
                list = ((SolrResultSet)rs).newGet(from, to, format, transformer, oldRefineTransformer);
431
            }
432

    
433

    
434
            searchResults = list.get("search");
435
            browseResults = list.get("refine");
436

    
437
        } catch (IndexServiceException ise) {
438
            logger.error("Error getting refine results.", ise);
439
            throw new SearchServiceException("Error getting refine results.", ise);
440

    
441
        }
442

    
443
        long estimatedTime = System.nanoTime() - startTime;
444
        logger.debug("Search time " + estimatedTime/1000000 +  " milliseconds for query " + query +
445
                " and fields " + fieldQueries + " and refine " + refinefields + " from: "+ from + " and size " + to);
446

    
447
        //logger.info("Returned results for NEW search query '" + query + "' and fields " + fieldQueries + " and refine " + refinefields);;
448
        rs.close();
449
        return new SearchResult(query, Locale.getDefault().toString(), rs.size(), from, to, searchResults, browseResults, refinefields);
450
    }
451

    
452

    
453
    public String getMdFormat() {
454
        return mdFormat;
455
    }
456

    
457
    public void setMdFormat(String mdFormat) {
458
        this.mdFormat = mdFormat;
459
    }
460

    
461
    public ServiceLocator<IndexService> getIndexLocator() {
462
        return indexLocator;
463
    }
464

    
465
    public void setIndexLocator(ServiceLocator<IndexService> indexLocator) {
466
        this.indexLocator = indexLocator;
467
    }
468

    
469
    public ResultSetFactory getRsFactory() {
470
        return rsFactory;
471
    }
472

    
473
    public void setRsFactory(ResultSetFactory rsFactory) {
474
        this.rsFactory = rsFactory;
475
    }
476

    
477
    public Collection<FieldRewriteRule> getFieldRules() {
478
        return fieldRules.values();
479
    }
480

    
481
    public List<QueryRewriteRule> getQueryRules() {
482
        return queryRules;
483
    }
484

    
485
    public void setQueryRules(List<QueryRewriteRule> queryRules) {
486
        this.queryRules = queryRules;
487
    }
488

    
489
    public boolean isEnableBrowseCache() {
490
        return enableBrowseCache;
491
    }
492

    
493
    public void setEnableBrowseCache(boolean enableBrowseCache) {
494
        this.enableBrowseCache = enableBrowseCache;
495
    }
496

    
497
    public SearchRegistry getTransformerFactory() {
498
        return transformerFactory;
499
    }
500

    
501
    public void setTransformerFactory(SearchRegistry transformerFactory) { this.transformerFactory = transformerFactory; }
502

    
503
    public String getIndexLayout() {
504
        return indexLayout;
505
    }
506

    
507
    public void setIndexLayout(String indexLayout) {
508
        this.indexLayout = indexLayout;
509
    }
510

    
511
    public SearchServiceBlackboardHandler getBlackboardNotificationHandler() {
512
        return blackboardNotificationHandler;
513
    }
514

    
515
    public void setBlackboardNotificationHandler(SearchServiceBlackboardHandler blackboardNotificationHandler) {
516
        this.blackboardNotificationHandler = blackboardNotificationHandler;
517
    }
518

    
519
    public void setLookUpServiceServiceLocator(ServiceLocator<ISLookUpService> lookUpServiceServiceLocator) {
520
        this.lookUpServiceServiceLocator = lookUpServiceServiceLocator;
521
    }
522

    
523
    public List<String> getFieldQueryRules() {
524
        return fieldQueryRules;
525
    }
526

    
527
    public void setFieldQueryRules(List<String> fieldQueryRules) {
528
        this.fieldQueryRules = fieldQueryRules;
529
    }
530
}
(2-2/2)