Project

General

Profile

« Previous | Next » 

Revision 16495c16

Added by Cherian Mathew about 11 years ago

NameCatalogueController : updated controller to improve exact and fuzzy name search to use lucene document only searches
NameSearch : updated dto to accomodate lucene documents

View differences:

cdmlib-remote/src/main/java/eu/etaxonomy/cdm/remote/controller/dto/NameCatalogueController.java
14 14
import java.util.List;
15 15
import java.util.Map;
16 16
import java.util.Set;
17
import java.util.StringTokenizer;
17 18
import java.util.TreeMap;
18 19
import java.util.UUID;
19 20

  
......
23 24
import java.util.Hashtable;
24 25

  
25 26
import org.apache.log4j.Level;
27
import org.apache.lucene.document.Document;
26 28
import org.apache.lucene.queryParser.ParseException;
27 29
import org.joda.time.DateTime;
28 30
import org.joda.time.format.DateTimeFormat;
......
42 44
import eu.etaxonomy.cdm.api.service.INameService;
43 45
import eu.etaxonomy.cdm.api.service.ITaxonService;
44 46
import eu.etaxonomy.cdm.api.service.ITermService;
47
import eu.etaxonomy.cdm.api.service.search.DocumentSearchResult;
45 48
import eu.etaxonomy.cdm.api.service.search.SearchResult;
46 49
import eu.etaxonomy.cdm.common.DocUtils;
47 50
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
51
import eu.etaxonomy.cdm.hibernate.search.AcceptedTaxonBridge;
48 52

  
49 53
import eu.etaxonomy.cdm.remote.controller.BaseController;
50 54
import eu.etaxonomy.cdm.remote.dto.common.ErrorResponse;
......
108 112

  
109 113
    /** Default name search type */
110 114
    public static final String DEFAULT_SEARCH_TYPE = NAME_SEARCH;
115
    
116
    /** Default max number of hits for the exact name search  */
117
    public static final String DEFAULT_MAX_NB_FOR_EXACT_SEARCH = "100";
111 118

  
112 119
    /** Classifcation 'default' key */
113 120
    public static final String CLASSIFICATION_DEFAULT = "default";
......
294 301
    @RequestMapping(value = { "" }, method = RequestMethod.GET, params = {"query"})
295 302
    public ModelAndView doGetNameSearch(@RequestParam(value = "query", required = true) String[] queries,
296 303
            HttpServletRequest request, HttpServletResponse response) throws IOException {
297
    return doGetNameSearch(queries, DEFAULT_SEARCH_TYPE, request, response);
304
    return doGetNameSearch(queries, DEFAULT_SEARCH_TYPE, DEFAULT_MAX_NB_FOR_EXACT_SEARCH, request, response);
298 305
    }
299 306

  
300 307
    /**
......
307 314
     * URI: <b>&#x002F;{datasource-name}&#x002F;name_catalogue</b>
308 315
     *
309 316
     * @param query
310
     *                The scientific name pattern(s) to query for. The query can
311
     *                contain wildcard characters ('*'). The query can be
312
     *                performed with no wildcard or with the wildcard at the
313
     *                begin and / or end depending on the search pattern.
317
     *             	The scientific name pattern(s) to query for. The query can
318
     *             	contain wildcard characters ('*'). The query can be
319
     *              performed with no wildcard or with the wildcard at the
320
     *              begin and / or end depending on the search pattern.
314 321
     * @param type
315
     *                The type of name to query. This be either
316
     *                "name" : scientific name corresponding to 'name cache' in CDM or
317
     *                "title" : complete name corresponding to 'title cache' in CDM
322
     *              The type of name to query. This be either
323
     *              "name" : scientific name corresponding to 'name cache' in CDM or
324
     *              "title" : complete name corresponding to 'title cache' in CDM
325
     * @param hits               
326
     *            	Maximum number of responses to be returned.    
318 327
     * @param request Http servlet request.
319 328
     * @param response Http servlet response.
320 329
     * @return a List of {@link NameSearch} objects each corresponding to a
......
325 334
    @RequestMapping(value = { "" }, method = RequestMethod.GET, params = {"query", "type"})
326 335
    public ModelAndView doGetNameSearch(@RequestParam(value = "query", required = true) String[] queries,
327 336
            @RequestParam(value = "type", required = false, defaultValue = DEFAULT_SEARCH_TYPE) String searchType,
337
            @RequestParam(value = "hits", required = false, defaultValue = DEFAULT_MAX_NB_FOR_EXACT_SEARCH) String hits,
328 338
            HttpServletRequest request, HttpServletResponse response) throws IOException {
329 339
        ModelAndView mv = new ModelAndView();
330 340
        List<RemoteResponse> nsList = new ArrayList<RemoteResponse>();
331 341

  
332
        // if search type is not known then return error
333
        if (!searchType.equals(NAME_SEARCH) && !searchType.equals(TITLE_SEARCH)) {
334
            ErrorResponse er = new ErrorResponse();
335
            er.setErrorMessage("searchType parameter can only be set as" + NAME_SEARCH + " or "
336
                    + TITLE_SEARCH);
337
            mv.addObject(er);
342
        int h = 100;
343
        try {        	
344
        	h = Integer.parseInt(hits);
345
        } catch(NumberFormatException nfe) {
346
        	ErrorResponse er = new ErrorResponse();
347
        	er.setErrorMessage("hits parameter is not a number");
348
        	mv.addObject(er);
338 349
            return mv;
339 350
        }
340

  
351
        
341 352
        // search through each query
342 353
        for (String query : queries) {
343

  
354
        	if(query.equals("")) {
355
				ErrorResponse er = new ErrorResponse();
356
                er.setErrorMessage("Empty query field");
357
                nsList.add(er);
358
                continue;
359
        	}
360
        	// remove wildcards if any
344 361
            String queryWOWildcards = getQueryWithoutWildCards(query);
345
            MatchMode mm = getMatchModeFromQuery(query);
346
            logger.info("doGetNameSearch()" + request.getRequestURI() + " for query \"" + query
347
                    + "\" without wild cards : " + queryWOWildcards + " and match mode : " + mm);
348
            List<NonViralName> nameList = new ArrayList<NonViralName>();
349

  
350
            // if "name" search then find by name cache
351
            if (searchType.equals(NAME_SEARCH)) {
352
                nameList = (List<NonViralName>) service.findNamesByNameCache(queryWOWildcards, mm,
353
                        NAME_SEARCH_INIT_STRATEGY);
354
            }
355

  
356
            //if "title" search then find by title cache
357
            if (searchType.equals(TITLE_SEARCH)) {
358
                nameList = (List<NonViralName>) service.findNamesByTitleCache(queryWOWildcards, mm,
359
                        NAME_SEARCH_INIT_STRATEGY);
362
            // convert first char to upper case
363
            char[] stringArray = queryWOWildcards.toCharArray();
364
            stringArray[0] = Character.toUpperCase(stringArray[0]);
365
            queryWOWildcards = new String(stringArray);
366
            
367
            boolean wc = false;
368
            
369
            if(getMatchModeFromQuery(query) == MatchMode.BEGINNING) {
370
            	wc = true;
360 371
            }
372
            logger.info("doGetNameSearch()" + request.getRequestURI() + " for query \"" + query);
373
            
374
            List<DocumentSearchResult> nameSearchList = new ArrayList<DocumentSearchResult>();
375
            try {            	            
376
				nameSearchList = service.findByNameExactSearch(
377
				        queryWOWildcards,
378
				        wc,
379
				        null,
380
				        false, 
381
				        h);
382
			} catch (ParseException e) {
383
				// TODO Auto-generated catch block
384
				//e.printStackTrace();
385
				ErrorResponse er = new ErrorResponse();
386
                er.setErrorMessage("Could not parse name : " + query);
387
                nsList.add(er);
388
                continue;
389
			} 
390
     
361 391

  
362 392
            // if search is successful then get related information , else return error
363
            if (nameList == null || !nameList.isEmpty()) {
393
            if (nameSearchList == null || !nameSearchList.isEmpty()) {
364 394
                NameSearch ns = new NameSearch();
365 395
                ns.setRequest(query);
366 396

  
367
                for (NonViralName nvn : nameList) {
397
                for (DocumentSearchResult searchResult : nameSearchList) {
398
                	for(Document doc : searchResult.getDocs()) {
399
                	
368 400
                    // we need to retrieve both taxon uuid of name queried and
369 401
                    // the corresponding accepted taxa.
370 402
                    // reason to return accepted taxa also, is to be able to get from
371 403
                    // scientific name to taxon concept in two web service calls.
372
                    Set<TaxonBase> tbSet = nvn.getTaxonBases();
373
                    Set<TaxonBase> accTbSet = new HashSet<TaxonBase>();
374
                    for (TaxonBase tb : tbSet) {
375
                        // if synonym then get accepted taxa.
376
                        if (tb instanceof Synonym) {
377
                            Synonym synonym = (Synonym) tb;
378
                            Set<SynonymRelationship> synRelationships = synonym.getSynonymRelations();
379
                            for (SynonymRelationship sr : synRelationships) {
380
                                Taxon accTaxon = sr.getAcceptedTaxon();
381
                                accTbSet.add(accTaxon);
382
                            }
383
                        } else {
384
                            accTbSet.add(tb);
385
                        }
404
                    List<String> tbUuidList = new ArrayList<String>();//nvn.getTaxonBases();
405
                    List<String> accTbUuidList = new ArrayList<String>();
406
                    String[] tbUuids = doc.getValues("taxonBases.uuid");
407
                    String[] tbClassNames = doc.getValues("taxonBases.classInfo.name");
408
                    for(int i=0;i<tbUuids.length;i++) {
409
                    	if(tbClassNames[i].equals("eu.etaxonomy.cdm.model.taxon.Taxon")) {
410
                    		accTbUuidList.add(tbUuids[i]);
411
                    	}
386 412
                    }
387 413
                    // update name search object
388
                    ns.addToResponseList(nvn.getTitleCache(), nvn.getNameCache(), 0, nvn.getUuid()
389
                            .toString(), tbSet, accTbSet);
414
                    ns.addToResponseList(doc.getValues("titleCache")[0], 
415
                    		doc.getValues("nameCache")[0], 
416
                    		searchResult.getMaxScore(), 
417
                    		doc.getValues("uuid")[0].toString(), 
418
                    		doc.getValues("taxonBases.uuid"),
419
                    		mergeSynAccTaxonUuids(doc.getValues("taxonBases.accTaxon.uuids")));
420
                	}
390 421
                }
391 422
                nsList.add(ns);
392 423

  
393 424
            } else {
394 425
                ErrorResponse er = new ErrorResponse();
395
                er.setErrorMessage("No Taxon Name for given query : " + query);
426
                er.setErrorMessage("No Taxon Name matches : " + query + ", for given accuracy");
396 427
                nsList.add(er);
397 428
            }
398 429
        }        
......
461 492
     */
462 493
    @RequestMapping(value = { "fuzzy" }, method = RequestMethod.GET, params = {"query"})
463 494
    public ModelAndView doGetNameFuzzySearch(@RequestParam(value = "query", required = true) String[] queries,
464
    		@RequestParam(value = "accuracy", required = false, defaultValue = "0.5") String accuracy,
495
    		@RequestParam(value = "accuracy", required = false, defaultValue = "0.6") String accuracy,
465 496
    		@RequestParam(value = "hits", required = false, defaultValue = "10") String hits,
466 497
            HttpServletRequest request, HttpServletResponse response) throws IOException {
467 498
        ModelAndView mv = new ModelAndView();
......
500 531
            queryWOWildcards = new String(stringArray);
501 532
            logger.info("doGetNameSearch()" + request.getRequestURI() + " for query \"" + queryWOWildcards + " with accuracy " + accuracy);
502 533
            //List<NonViralName> nameList = new ArrayList<NonViralName>();
503
            List<SearchResult<TaxonNameBase>> nameSearchList = new ArrayList<SearchResult<TaxonNameBase>>();
534
            List<DocumentSearchResult> nameSearchList = new ArrayList<DocumentSearchResult>();
504 535
            try {            	            
505 536
				nameSearchList = service.findByNameFuzzySearch(
506 537
				        queryWOWildcards,
507 538
				        acc,
508 539
				        null,
509 540
				        false, 
510
				        NAME_SEARCH_INIT_STRATEGY,
511 541
				        h);
512 542
			} catch (ParseException e) {
513 543
				// TODO Auto-generated catch block
......
524 554
                NameSearch ns = new NameSearch();
525 555
                ns.setRequest(query);
526 556

  
527
                for (SearchResult searchResult : nameSearchList) {
528
                	NonViralName nvn = HibernateProxyHelper.deproxy(searchResult.getEntity(), NonViralName.class);
557
                for (DocumentSearchResult searchResult : nameSearchList) {
558
                	for(Document doc : searchResult.getDocs()) {
529 559
                	
530 560
                    // we need to retrieve both taxon uuid of name queried and
531 561
                    // the corresponding accepted taxa.
532 562
                    // reason to return accepted taxa also, is to be able to get from
533 563
                    // scientific name to taxon concept in two web service calls.
534
                    Set<TaxonBase> tbSet = nvn.getTaxonBases();
535
                    Set<TaxonBase> accTbSet = new HashSet<TaxonBase>();
536
                    for (TaxonBase tb : tbSet) {
537
                        // if synonym then get accepted taxa.
538
                        if (tb instanceof Synonym) {
539
                            Synonym synonym = (Synonym) tb;
540
                            Set<SynonymRelationship> synRelationships = synonym.getSynonymRelations();
541
                            for (SynonymRelationship sr : synRelationships) {
542
                                Taxon accTaxon = sr.getAcceptedTaxon();
543
                                accTbSet.add(accTaxon);
544
                            }
545
                        } else {
546
                            accTbSet.add(tb);
547
                        }
564
                    List<String> tbUuidList = new ArrayList<String>();//nvn.getTaxonBases();
565
                    List<String> accTbUuidList = new ArrayList<String>();
566
                    String[] tbUuids = doc.getValues("taxonBases.uuid");
567
                    String[] tbClassNames = doc.getValues("taxonBases.classInfo.name");
568
                    for(int i=0;i<tbUuids.length;i++) {
569
                    	if(tbClassNames[i].equals("eu.etaxonomy.cdm.model.taxon.Taxon")) {
570
                    		accTbUuidList.add(tbUuids[i]);
571
                    	}
548 572
                    }
549 573
                    // update name search object
550
                    ns.addToResponseList(nvn.getTitleCache(), nvn.getNameCache(), searchResult.getMaxScore(), nvn.getUuid()
551
                            .toString(), tbSet, accTbSet);
574
                    ns.addToResponseList(doc.getValues("titleCache")[0], 
575
                    		doc.getValues("nameCache")[0], 
576
                    		searchResult.getMaxScore(), 
577
                    		doc.getValues("uuid")[0].toString(), 
578
                    		doc.getValues("taxonBases.uuid"),
579
                    		mergeSynAccTaxonUuids(doc.getValues("taxonBases.accTaxon.uuids")));
580
                	}
552 581
                }
553 582
                nsList.add(ns);
554 583

  
......
562 591
        mv.addObject(nsList);
563 592
        return mv;
564 593
    }
565

  
594
    
595
    private String[] mergeSynAccTaxonUuids(String[] accTaxonUuids) {
596
    	List<String> accTaxonUuidList = new ArrayList<String>();
597
    	for(String accTaxonUuid : accTaxonUuids) {
598
    		for(String uuidListAsString : accTaxonUuid.split(AcceptedTaxonBridge.ACCEPTED_TAXON_UUID_LIST_SEP)) {
599
    			accTaxonUuidList.add(uuidListAsString);
600
    		}
601
    	}
602
    	return accTaxonUuidList.toArray(new String[0]);
603
    	
604
    }
566 605
    /**
567 606
     * Returns a documentation page for the Name Information API.
568 607
     * <p>
......
797 836
                        String title = syn.getTitleCache();
798 837
                        TaxonNameBase synnvn = (TaxonNameBase) syn.getName();
799 838
                        String name = synnvn.getTitleCache();
800
                        String rank = synnvn.getRank().getTitleCache();
839
                        String rank = (synnvn.getRank() == null)? "" : synnvn.getRank().getTitleCache();
801 840
                        String status = SYNONYM_STATUS;
802 841
                        String relLabel = sr.getType()
803 842
                                .getInverseRepresentation(Language.DEFAULT())
......
1068 1107
        ModelAndView mv = new ModelAndView();
1069 1108
        List<RemoteResponse> ansList = new ArrayList<RemoteResponse>();
1070 1109
        logger.info("doGetAcceptedNameSearch()");
1110
        
1071 1111
        // if search type is not known then return error
1072 1112
        if (!searchType.equals(NAME_SEARCH) && !searchType.equals(TITLE_SEARCH)) {
1073 1113
            ErrorResponse er = new ErrorResponse();
cdmlib-remote/src/main/java/eu/etaxonomy/cdm/remote/dto/namecatalogue/NameSearch.java
61 61
            res.addToAcceptedTaxontUuids(acctb.getUuid().toString());
62 62
        }
63 63
    }
64
    
65
    public void addToResponseList(String title, 
66
    		String name, 
67
    		float score, 
68
    		String nameUuid, 
69
    		String[] taxonBaseUuids,
70
    		String[] accTaxonUuids) {
71

  
72
        NameSearch.NameSearchResponse res = responseWithtitle(title);
73
        if (res == null) {
74
            res = new NameSearch.NameSearchResponse();
75
            res.setTitle(title);
76
            res.setName(name);
77
            res.setScore(score);
78
            response.add(res);
79
        }
80
        res.addToNameUuids(nameUuid);
81
        for (String tbuuid : taxonBaseUuids) {
82
            res.addToTaxonConceptUuids(tbuuid);
83
        }
84
        for (String acctbuuid : accTaxonUuids) {
85
            res.addToAcceptedTaxontUuids(acctbuuid);
86
        }
87
    }
64 88

  
65 89
    public List<NameSearch.NameSearchResponse> getResponse() {
66 90
        return this.response;

Also available in: Unified diff