Project

General

Profile

Download (99.9 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
 * Copyright (C) 2009 EDIT
3
 * European Distributed Institute of Taxonomy
4
 * http://www.e-taxonomy.eu
5
 *
6
 * The contents of this file are subject to the Mozilla Public License Version 1.1
7
 * See LICENSE.TXT at the top of this package for the full license terms.
8
 */
9

    
10
package eu.etaxonomy.cdm.api.service;
11

    
12
import static org.junit.Assert.assertNotNull;
13

    
14
import java.io.FileNotFoundException;
15
import java.io.IOException;
16
import java.util.ArrayList;
17
import java.util.Arrays;
18
import java.util.EnumSet;
19
import java.util.HashSet;
20
import java.util.List;
21
import java.util.Map;
22
import java.util.Set;
23
import java.util.UUID;
24

    
25
import org.apache.commons.lang.RandomStringUtils;
26
import org.apache.log4j.Level;
27
import org.apache.log4j.Logger;
28
import org.apache.lucene.document.Document;
29
import org.junit.Assert;
30
import org.junit.Before;
31
import org.junit.Ignore;
32
import org.junit.Test;
33
import org.unitils.dbunit.annotation.DataSet;
34
import org.unitils.spring.annotation.SpringBeanByType;
35

    
36
import eu.etaxonomy.cdm.api.service.config.FindTaxaAndNamesConfiguratorImpl;
37
import eu.etaxonomy.cdm.api.service.config.IFindTaxaAndNamesConfigurator;
38
import eu.etaxonomy.cdm.api.service.pager.Pager;
39
import eu.etaxonomy.cdm.api.service.search.ICdmMassIndexer;
40
import eu.etaxonomy.cdm.api.service.search.LuceneMultiSearchException;
41
import eu.etaxonomy.cdm.api.service.search.LuceneParseException;
42
import eu.etaxonomy.cdm.api.service.search.SearchResult;
43
import eu.etaxonomy.cdm.common.UTF8;
44
import eu.etaxonomy.cdm.common.monitor.DefaultProgressMonitor;
45
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
46
import eu.etaxonomy.cdm.model.common.CdmBase;
47
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
48
import eu.etaxonomy.cdm.model.common.Language;
49
import eu.etaxonomy.cdm.model.description.CategoricalData;
50
import eu.etaxonomy.cdm.model.description.CommonTaxonName;
51
import eu.etaxonomy.cdm.model.description.DescriptionBase;
52
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
53
import eu.etaxonomy.cdm.model.description.Distribution;
54
import eu.etaxonomy.cdm.model.description.Feature;
55
import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
56
import eu.etaxonomy.cdm.model.description.State;
57
import eu.etaxonomy.cdm.model.description.StateData;
58
import eu.etaxonomy.cdm.model.description.TaxonDescription;
59
import eu.etaxonomy.cdm.model.description.TextData;
60
import eu.etaxonomy.cdm.model.location.Country;
61
import eu.etaxonomy.cdm.model.location.NamedArea;
62
import eu.etaxonomy.cdm.model.name.IBotanicalName;
63
import eu.etaxonomy.cdm.model.name.Rank;
64
import eu.etaxonomy.cdm.model.name.TaxonName;
65
import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
66
import eu.etaxonomy.cdm.model.reference.Reference;
67
import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
68
import eu.etaxonomy.cdm.model.taxon.Classification;
69
import eu.etaxonomy.cdm.model.taxon.Synonym;
70
import eu.etaxonomy.cdm.model.taxon.SynonymType;
71
import eu.etaxonomy.cdm.model.taxon.Taxon;
72
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
73
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
74
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
75
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
76
import eu.etaxonomy.cdm.model.term.DefinedTermBase;
77
import eu.etaxonomy.cdm.persistence.query.MatchMode;
78
import eu.etaxonomy.cdm.persistence.query.OrderHint;
79
import eu.etaxonomy.cdm.test.integration.CdmTransactionalIntegrationTest;
80
import eu.etaxonomy.cdm.test.unitils.CleanSweepInsertLoadStrategy;
81

    
82
/**
83
 * @author a.babadshanjan, a.kohlbecker
84
 * @since 04.02.2009
85
 */
86
public class TaxonServiceSearchTest extends CdmTransactionalIntegrationTest {
87

    
88
    private static Logger logger = Logger.getLogger(TaxonServiceSearchTest.class);
89

    
90
    private static final int BENCHMARK_ROUNDS = 300;
91

    
92
    private static final UUID ABIES_BALSAMEA_UUID = UUID.fromString("f65d47bd-4f49-4ab1-bc4a-bc4551eaa1a8");
93
    private static final UUID ABIES_ALBA_UUID = UUID.fromString("7dbd5810-a3e5-44b6-b563-25152b8867f4");
94
    private static final UUID CLASSIFICATION_UUID = UUID.fromString("2a5ceebb-4830-4524-b330-78461bf8cb6b");
95
    private static final UUID CLASSIFICATION_ALT_UUID = UUID.fromString("d7c741e3-ae9e-4a7d-a566-9e3a7a0b51ce");
96
    private static final UUID ABIES_SUBALPINA_UUID = UUID.fromString("9fee273c-c819-4f1f-913a-cd910465df51");
97
    private static final UUID ABIES_LASIOCARPA_UUID = UUID.fromString("9ce1fecf-c1ad-4127-be01-85d5d9f847ce");
98

    
99
    private static final UUID ROOTNODE_CLASSIFICATION_5000 = UUID.fromString("a8266e45-091f-432f-87ae-c625e6aa9bbc");
100

    
101
    private static final UUID DESC_ABIES_BALSAMEA_UUID = UUID.fromString("900108d8-e6ce-495e-b32e-7aad3099135e");
102
    private static final UUID DESC_ABIES_ALBA_UUID = UUID.fromString("ec8bba03-d993-4c85-8472-18b14942464b");
103
    private static final UUID DESC_ABIES_KAWAKAMII_SEC_KOMAROV_UUID = UUID.fromString("e9d8c2fd-6409-46d5-9c2e-14a2bbb1b2b1");
104

    
105
    private static final int NUM_OF_NEW_RADOM_ENTITIES = 1000;
106

    
107
    private boolean includeUnpublished = true;
108

    
109
    @SpringBeanByType
110
    private ITaxonService taxonService;
111
    @SpringBeanByType
112
    private ITermService termService;
113
    @SpringBeanByType
114
    private IClassificationService classificationService;
115
    @SpringBeanByType
116
    private IReferenceService referenceService;
117
    @SpringBeanByType
118
    private IDescriptionService descriptionService;
119
    @SpringBeanByType
120
    private IDescriptionElementService descriptionElementService;
121
    @SpringBeanByType
122
    private INameService nameService;
123
    @SpringBeanByType
124
    private ITaxonNodeService nodeService;
125

    
126
    @SpringBeanByType
127
    private ICdmMassIndexer indexer;
128

    
129
    private Set<Class<? extends CdmBase>> typesToIndex = null;
130

    
131
    private NamedArea germany;
132
    private NamedArea france;
133
    private NamedArea russia;
134
    private NamedArea canada;
135

    
136
    @Before
137
    public void setUp() throws Exception {
138
        typesToIndex = new HashSet<>();
139
        typesToIndex.add(DescriptionElementBase.class);
140
        typesToIndex.add(TaxonBase.class);
141
        typesToIndex.add(TaxonRelationship.class);
142

    
143
        germany =  Country.GERMANY();
144
        france = Country.FRANCEFRENCHREPUBLIC();
145
        russia = Country.RUSSIANFEDERATION();
146
        canada = Country.CANADA();
147

    
148
        includeUnpublished = true;
149
    }
150

    
151
    @Test
152
    public void testDbUnitUsageTest() throws Exception {
153
        assertNotNull("taxonService should exist", taxonService);
154
        assertNotNull("nameService should exist", nameService);
155
    }
156

    
157
    @SuppressWarnings("rawtypes")
158
    @Test
159
    @DataSet
160
    public final void testPurgeAndReindex() throws IOException, LuceneParseException {
161

    
162
        refreshLuceneIndex();
163
        TaxonNode subtree = null;
164

    
165
        Pager<SearchResult<TaxonBase>> pager = taxonService.findByFullText(null, "Abies", null, subtree,
166
                includeUnpublished, null, true, null, null, null, null); // --> 8
167
        Assert.assertEquals("Expecting 8 entities", 8, pager.getCount().intValue());
168

    
169
        indexer.purge(null);
170
        commitAndStartNewTransaction(null);
171

    
172
        pager = taxonService.findByFullText(null, "Abies", null, subtree, includeUnpublished, null, true, null, null, null, null); // --> 0
173
        Assert.assertEquals("Expecting no entities since the index has been purged", 0, pager.getCount().intValue());
174

    
175
        indexer.reindex(indexer.indexedClasses(), null);
176
        commitAndStartNewTransaction(null);
177

    
178
        pager = taxonService.findByFullText(null, "Abies", null, subtree, includeUnpublished, null, true, null, null, null, null); // --> 8
179
        Assert.assertEquals("Expecting 8 entities", 8, pager.getCount().intValue());
180
    }
181

    
182
    @SuppressWarnings("rawtypes")
183
    @Test
184
    @DataSet
185
    public final void testFindByDescriptionElementFullText_CommonName() throws IOException,
186
            LuceneParseException {
187

    
188
        TaxonNode subtree = null;
189
        refreshLuceneIndex();
190

    
191
        Pager<SearchResult<TaxonBase>> pager = taxonService.findByDescriptionElementFullText(CommonTaxonName.class, "Wei"+UTF8.SHARP_S+"tanne",
192
                null, subtree, null, null,
193
                false, null, null, null, null);
194
        Assert.assertEquals("Expecting one entity when searching for CommonTaxonName", 1,
195
                pager.getCount().intValue());
196

    
197
        // the description containing the Nulltanne has no taxon attached,
198
        // taxon.id = null
199
        pager = taxonService.findByDescriptionElementFullText(CommonTaxonName.class, "Nulltanne", null, subtree, null, null,
200
                false, null, null, null, null);
201
        Assert.assertEquals("Expecting no entity when searching for 'Nulltanne' ", 0, pager.getCount().intValue());
202

    
203
        pager = taxonService.findByDescriptionElementFullText(CommonTaxonName.class, "Wei"+UTF8.SHARP_S+"tanne", null, subtree, null,
204
                Arrays.asList(new Language[] { Language.GERMAN() }), false, null, null, null, null);
205
        Assert.assertEquals("Expecting one entity when searching in German", 1, pager.getCount().intValue());
206

    
207
        pager = taxonService.findByDescriptionElementFullText(CommonTaxonName.class, "Wei"+UTF8.SHARP_S+"tanne", null, subtree, null,
208
                Arrays.asList(new Language[] { Language.RUSSIAN() }), false, null, null, null, null);
209
        Assert.assertEquals("Expecting no entity when searching in Russian", 0, pager.getCount().intValue());
210
    }
211

    
212
    @SuppressWarnings("rawtypes")
213
    @Test
214
    @DataSet
215
    public final void testFindByDescriptionElementFullText_Distribution() throws IOException, LuceneParseException {
216

    
217
        refreshLuceneIndex();
218
        TaxonNode subtree = null;
219

    
220
        // by Area
221
        Pager<SearchResult<TaxonBase>>  pager = taxonService.findByDescriptionElementFullText(null, "Canada", null, subtree, null, null, false, null, null, null, null);
222
        Assert.assertEquals("Expecting one entity when searching for arae 'Canada'", 1, pager.getCount().intValue());
223
        // by Status
224
        pager = taxonService.findByDescriptionElementFullText(null, "present", null, subtree, null, null, false, null, null, null, null);
225
        Assert.assertEquals("Expecting one entity when searching for status 'present'", 1, pager.getCount().intValue());
226
    }
227

    
228
    @SuppressWarnings("rawtypes")
229
    @Test
230
    @DataSet
231
    public final void testFindByDescriptionElementFullText_wildcard() throws IOException, LuceneParseException {
232

    
233
        refreshLuceneIndex();
234
        TaxonNode subtree = null;
235

    
236
        Pager<SearchResult<TaxonBase>> pager = taxonService.findByDescriptionElementFullText(CommonTaxonName.class, "Wei"+UTF8.SHARP_S+"*", null, subtree, null, null, false, null, null, null, null);
237
        Assert.assertEquals("Expecting one entity when searching for CommonTaxonName", 1, pager.getCount().intValue());
238
    }
239

    
240
    /**
241
     * Regression test for #3113 (hibernate search: wildcard query can cause BooleanQuery$TooManyClauses: maxClauseCount is set to 1024)
242
     *
243
     * @throws IOException
244
     * @throws LuceneParseException
245
     */
246
    @SuppressWarnings("rawtypes")
247
    @Test
248
    @DataSet
249
    public final void testFindByDescriptionElementFullText_TooManyClauses() throws IOException, LuceneParseException {
250

    
251
        TaxonNode subtree = null;
252

    
253
        // generate 1024 terms to reproduce the bug
254
        TaxonDescription description = (TaxonDescription) descriptionService.find(DESC_ABIES_ALBA_UUID);
255
        Set<String> uniqueRandomStrs = new HashSet<>(1024);
256
        while(uniqueRandomStrs.size() < 1024){
257
            uniqueRandomStrs.add(RandomStringUtils.random(10, true, false));
258
        }
259
        for(String rndStr: uniqueRandomStrs){
260
            description.addElement(CommonTaxonName.NewInstance("Rot" + rndStr, Language.DEFAULT()));
261
        }
262
        descriptionService.saveOrUpdate(description);
263
        commitAndStartNewTransaction(null);
264

    
265
        refreshLuceneIndex();
266

    
267
        Pager<SearchResult<TaxonBase>> pager = taxonService.findByDescriptionElementFullText(CommonTaxonName.class, "Rot*", null, subtree, null, null, false, null, null, null, null);
268
        Assert.assertEquals("Expecting all 1024 entities grouped into one SearchResult item when searching for Rot*", 1, pager.getCount().intValue());
269
    }
270

    
271
    /**
272
     * Regression test for #3116 (fulltext search: always only one page of results)
273
     *
274
     * @throws IOException
275
     * @throws LuceneParseException
276
     */
277
    @SuppressWarnings("rawtypes")
278
    @Test
279
    @DataSet(loadStrategy=CleanSweepInsertLoadStrategy.class)
280
    public final void testFullText_Paging() throws IOException, LuceneParseException {
281

    
282
        TaxonNode subtree = null;
283
        Reference sec = ReferenceFactory.newDatabase();
284
        referenceService.save(sec);
285

    
286
        Set<String> uniqueRandomStrs = new HashSet<>(1024);
287
        int numOfItems = 100;
288
        while(uniqueRandomStrs.size() < numOfItems){
289
            uniqueRandomStrs.add(RandomStringUtils.random(5, true, false));
290
        }
291

    
292
        for(String rndStr: uniqueRandomStrs){
293

    
294
            Taxon taxon = Taxon.NewInstance(TaxonNameFactory.NewBotanicalInstance(Rank.SERIES()), sec);
295
            taxon.setTitleCache("Tax" + rndStr, true);
296
            taxonService.save(taxon);
297

    
298
            TaxonDescription description = TaxonDescription.NewInstance(taxon);
299
            description.addElement(CommonTaxonName.NewInstance("Rot" + rndStr, Language.DEFAULT()));
300
            descriptionService.saveOrUpdate(description);
301
        }
302

    
303
        commitAndStartNewTransaction(new String[]{/*"TAXONBASE"*/});
304
        refreshLuceneIndex();
305

    
306
        int pageSize = 10;
307

    
308
        Pager<SearchResult<TaxonBase>> pager = taxonService.findByDescriptionElementFullText(CommonTaxonName.class, "Rot*", null, subtree, null, null, false, pageSize, null, null, null);
309
        Assert.assertEquals("unexpeted number of pages", Integer.valueOf(numOfItems / pageSize), pager.getPagesAvailable());
310
        pager = taxonService.findByDescriptionElementFullText(CommonTaxonName.class, "Rot*", null, subtree, null, null, false, pageSize, 9, null, null);
311
        Assert.assertNotNull("last page must have records", pager.getRecords());
312
        Assert.assertNotNull("last item on last page must exist", pager.getRecords().get(0));
313
        pager = taxonService.findByDescriptionElementFullText(CommonTaxonName.class, "Rot*", null, subtree, null, null, false, pageSize, 10, null, null);
314
        Assert.assertNotNull("last page + 1 must not have any records", pager.getRecords());
315
    }
316

    
317
    /**
318
     * test for max score and sort by score of hit groups
319
     * with all matches per taxon in a single TextData  element
320
     * see {@link #testFullText_ScoreAndOrder_2()} for the complement
321
     * test with matches in multiple TextData per taxon
322
     *
323
     * @throws IOException
324
     * @throws LuceneParseException
325
     */
326
    @SuppressWarnings("rawtypes")
327
    @Test
328
    @DataSet
329
    @Ignore // test fails, maybe the assumptions made here are not compatible with the lucene scoring mechanism see http://lucene.apache.org/core/3_6_1/scoring.html
330
    public final void testFullText_ScoreAndOrder_1() throws IOException, LuceneParseException {
331

    
332
        TaxonNode subtree = null;
333
        int numOfTaxa = 3;
334

    
335
        UUID[] taxonUuids = new UUID[numOfTaxa];
336
        StringBuilder text = new StringBuilder();
337

    
338
        for(int i = 0; i < numOfTaxa; i++){
339

    
340
            Taxon taxon = Taxon.NewInstance(TaxonNameFactory.NewBotanicalInstance(null), null);
341
            taxon.setTitleCache("Taxon_" + i, true);
342
            taxonUuids[i] = taxon.getUuid();
343
            taxonService.save(taxon);
344

    
345
            text.append(" ").append("Rot");
346
            TaxonDescription description = TaxonDescription.NewInstance(taxon);
347
            description.addElement(TextData.NewInstance(text.toString(), Language.DEFAULT(), null));
348
            descriptionService.saveOrUpdate(description);
349
        }
350

    
351
        commitAndStartNewTransaction(null);
352
        refreshLuceneIndex();
353

    
354
        Pager<SearchResult<TaxonBase>> pager = taxonService.findByDescriptionElementFullText(TextData.class, "Rot", null, subtree, null, null, false, null, null, null, null);
355
        for(int i = 0; i < numOfTaxa; i++){
356
            Assert.assertEquals("taxa should be orderd by relevance (= score)", taxonUuids[numOfTaxa - i - 1], pager.getRecords().get(i).getEntity().getUuid());
357
        }
358
        Assert.assertEquals("max score should be equal to the score of the first element", pager.getRecords().get(0).getMaxScore(), pager.getRecords().get(0).getScore(), 0);
359
    }
360

    
361
    /**
362
     * test for max score and sort by score of hit groups
363
     * with all matches per taxon in a multiple TextData elements
364
     * see {@link #testFullText_ScoreAndOrder_1()} for the complement
365
     * test with matches in a single TextData per taxon
366
     *
367
     * @throws IOException
368
     * @throws LuceneParseException
369
     */
370
    @SuppressWarnings("rawtypes")
371
    @Test
372
    @DataSet
373
    @Ignore // test fails, maybe the assumptions made here are not compatible with the lucene scoring mechanism see http://lucene.apache.org/core/3_6_1/scoring.html
374
    public final void testFullText_ScoreAndOrder_2() throws IOException, LuceneParseException {
375

    
376
        TaxonNode subtree = null;
377
        int numOfTaxa = 3;
378

    
379
        UUID[] taxonUuids = new UUID[numOfTaxa];
380

    
381
        for(int i = 0; i < numOfTaxa; i++){
382

    
383
            Taxon taxon = Taxon.NewInstance(TaxonNameFactory.NewBotanicalInstance(null), null);
384
            taxon.setTitleCache("Taxon_" + i, true);
385
            taxonUuids[i] = taxon.getUuid();
386
            taxonService.save(taxon);
387

    
388
            TaxonDescription description = TaxonDescription.NewInstance(taxon);
389
            for(int k = 0; k < i; k++){
390
                description.addElement(TextData.NewInstance("Rot", Language.DEFAULT(), null));
391
            }
392
            descriptionService.saveOrUpdate(description);
393
        }
394

    
395
        commitAndStartNewTransaction(null);
396
        refreshLuceneIndex();
397

    
398
        Pager<SearchResult<TaxonBase>> pager = taxonService.findByDescriptionElementFullText(TextData.class, "Rot", null, subtree, null, null, false, null, null, null, null);
399
        for(int i = 0; i < numOfTaxa; i++){
400
            Assert.assertEquals("taxa should be orderd by relevance (= score)", taxonUuids[numOfTaxa - i - 1], pager.getRecords().get(i).getEntity().getUuid());
401
        }
402
        Assert.assertEquals("max score should be equal to the score of the first element", pager.getRecords().get(0).getMaxScore(), pager.getRecords().get(0).getScore(), 0);
403
    }
404

    
405

    
406
    /**
407
     * @throws IOException
408
     * @throws LuceneParseException
409
     * @throws LuceneMultiSearchException
410
     */
411
    @Test
412
    @DataSet
413
    public final void testFullText_Grouping() throws IOException, LuceneParseException, LuceneMultiSearchException {
414

    
415
        TaxonNode subtree = null;
416
        TaxonDescription description = (TaxonDescription) descriptionService.find(DESC_ABIES_ALBA_UUID);
417
        Set<String> uniqueRandomStrs = new HashSet<>(1024);
418
        int numOfItems = 100;
419
        while(uniqueRandomStrs.size() < numOfItems){
420
            uniqueRandomStrs.add(RandomStringUtils.random(5, true, false));
421
        }
422
        for(String rndStr: uniqueRandomStrs){
423
            description.addElement(CommonTaxonName.NewInstance("Rot" + rndStr, Language.DEFAULT()));
424
        }
425
        descriptionService.saveOrUpdate(description);
426

    
427
        commitAndStartNewTransaction(new String[]{"DESCRIPTIONELEMENTBASE"});
428

    
429
        refreshLuceneIndex();
430

    
431
        int pageSize = 10;
432

    
433
         boolean highlightFragments = true;
434

    
435
        // test with findByDescriptionElementFullText
436
        Pager<SearchResult<TaxonBase>> pager = taxonService.findByDescriptionElementFullText(CommonTaxonName.class, "Rot*", null, subtree, null, null, highlightFragments, pageSize, null, null, null);
437
        logFreeTextSearchResults(pager, Level.DEBUG, null);
438
        Assert.assertEquals("All matches should be grouped into a single SearchResult element", 1, pager.getRecords().size());
439
        Assert.assertEquals("The count property of the pager must be set correctly", 1, pager.getCount().intValue());
440
        Map<String, String[]> highlightMap = pager.getRecords().get(0).getFieldHighlightMap();
441
        // maxDocsPerGroup is defined in LuceneSearch and defaults to 10
442
        int maxDocsPerGroup = 10;
443
        Assert.assertEquals("expecting 10 highlighted fragments of field 'name'", maxDocsPerGroup, highlightMap.get("name").length);
444

    
445
        // test with findByEverythingFullText
446
        pager = taxonService.findByEverythingFullText( "Rot*", null, subtree, includeUnpublished, null, highlightFragments, pageSize, null, null, null);
447
        logFreeTextSearchResults(pager, Level.DEBUG, null);
448
        Assert.assertEquals("All matches should be grouped into a single SearchResult element", 1, pager.getRecords().size());
449
        Assert.assertEquals("The count property of the pager must be set correctly", 1, pager.getCount().intValue());
450
        highlightMap = pager.getRecords().get(0).getFieldHighlightMap();
451
        // maxDocsPerGroup is defined in LuceneSearch and defaults to 10
452
        maxDocsPerGroup = 10;
453
        Assert.assertEquals("expecting 10 highlighted fragments of field 'name'", maxDocsPerGroup, highlightMap.get("name").length);
454

    
455
    }
456

    
457
    @SuppressWarnings("rawtypes")
458
    @Test
459
    @DataSet
460
    public final void testFindByDescriptionElementFullText_TextData() throws IOException, LuceneParseException {
461

    
462
        refreshLuceneIndex();
463
        TaxonNode subtree = null;
464

    
465
        Pager<SearchResult<TaxonBase>> pager = taxonService.findByDescriptionElementFullText(TextData.class, "Abies", null, subtree, null, null, false, null, null, null, null);
466
        logFreeTextSearchResults(pager, Level.DEBUG, null);
467
        Assert.assertEquals("Expecting one entity when searching for any TextData", 1, pager.getCount().intValue());
468
        Assert.assertEquals("Abies balsamea sec. Kohlbecker, A., Testcase standart views, 2013", pager.getRecords().get(0).getEntity().getTitleCache());
469
        Assert.assertTrue("Expecting two docs, one for RUSSIAN and one for GERMAN", pager.getRecords().get(0).getDocs().size() == 2);
470
        Assert.assertEquals("Abies balsamea sec. Kohlbecker, A., Testcase standart views, 2013", pager.getRecords().get(0).getDocs().iterator().next().get("inDescription.taxon.titleCache"));
471

    
472

    
473
        pager = taxonService.findByDescriptionElementFullText(null, "Abies", null, subtree, null, null, false, null, null, null, null);
474
        Assert.assertEquals("Expecting one entity when searching for any type", 1, pager.getCount().intValue());
475

    
476
        pager = taxonService.findByDescriptionElementFullText(null, "Abies", null, subtree, Arrays.asList(new Feature[]{Feature.UNKNOWN()}), null, false, null, null, null, null);
477
        Assert.assertEquals("Expecting one entity when searching for any type and for Feature DESCRIPTION", 1, pager.getCount().intValue());
478

    
479
        pager = taxonService.findByDescriptionElementFullText(null, "Abies", null, subtree, Arrays.asList(new Feature[]{Feature.CHROMOSOME_NUMBER()}), null, false, null, null, null, null);
480
        Assert.assertEquals("Expecting no entity when searching for any type and for Feature CHROMOSOME_NUMBER", 0, pager.getCount().intValue());
481

    
482
        pager = taxonService.findByDescriptionElementFullText(null, "Abies", null, subtree, Arrays.asList(new Feature[]{Feature.CHROMOSOME_NUMBER(), Feature.UNKNOWN()}), null, false, null, null, null, null);
483
        Assert.assertEquals("Expecting no entity when searching for any type and for Feature DESCRIPTION or CHROMOSOME_NUMBER", 1, pager.getCount().intValue());
484

    
485
        pager = taxonService.findByDescriptionElementFullText(Distribution.class, "Abies", null, subtree, null, null, false, null, null, null, null);
486
        Assert.assertEquals("Expecting no entity when searching for Distribution", 0, pager.getCount().intValue());
487

    
488
        pager = taxonService.findByDescriptionElementFullText(TextData.class, "Бальзам", null, subtree, null, Arrays.asList(new Language[]{}), false, null, null, null, null);
489
        Assert.assertEquals("Expecting one entity", 1, pager.getCount().intValue());
490
        Assert.assertEquals("Abies balsamea sec. Kohlbecker, A., Testcase standart views, 2013", pager.getRecords().get(0).getEntity().getTitleCache());
491

    
492
        pager = taxonService.findByDescriptionElementFullText(TextData.class, "Бальзам", null, subtree, null, Arrays.asList(new Language[]{Language.RUSSIAN()}), false, null, null, null, null);
493
        Assert.assertEquals("Expecting one entity", 1, pager.getCount().intValue());
494
        Assert.assertEquals("Abies balsamea sec. Kohlbecker, A., Testcase standart views, 2013", pager.getRecords().get(0).getEntity().getTitleCache());
495

    
496
        pager = taxonService.findByDescriptionElementFullText(TextData.class, "Бальзам", null, subtree, null, Arrays.asList(new Language[]{Language.GERMAN()}), false, null, null, null, null);
497
        Assert.assertEquals("Expecting no entity", 0, pager.getCount().intValue());
498

    
499
        pager = taxonService.findByDescriptionElementFullText(TextData.class, "Balsam-Tanne", null, subtree, null, Arrays.asList(new Language[]{Language.GERMAN(), Language.RUSSIAN()}), false, null, null, null, null);
500
        Assert.assertEquals("Expecting one entity", 1, pager.getCount().intValue());
501
        Assert.assertEquals("Abies balsamea sec. Kohlbecker, A., Testcase standart views, 2013", pager.getRecords().get(0).getEntity().getTitleCache());
502
    }
503

    
504
    @SuppressWarnings("rawtypes")
505
    @Test
506
    @DataSet
507
    public final void testFindByDescriptionElementFullText_MultipleWords() throws IOException, LuceneParseException {
508

    
509
        refreshLuceneIndex();
510
        TaxonNode subtree = null;
511

    
512
        // Pflanzenart aus der Gattung der Tannen
513
        long start = System.currentTimeMillis();
514

    
515
        Pager<SearchResult<TaxonBase>> pager = taxonService.findByDescriptionElementFullText(TextData.class, "Pflanzenart Tannen", null, subtree, null, null, false, null, null, null, null);
516
        Assert.assertEquals("OR search : Expecting one entity", 1, pager.getCount().intValue());
517

    
518
        pager = taxonService.findByDescriptionElementFullText(TextData.class, "Pflanzenart Wespen", null, subtree, null, null, false, null, null, null, null);
519
        Assert.assertEquals("OR search : Expecting one entity", 1, pager.getCount().intValue());
520

    
521
        pager = taxonService.findByDescriptionElementFullText(TextData.class, "+Pflanzenart +Tannen", null, subtree, null, null, false, null, null, null, null);
522
        Assert.assertEquals("AND search : Expecting one entity", 1, pager.getCount().intValue());
523

    
524
        pager = taxonService.findByDescriptionElementFullText(TextData.class, "+Pflanzenart +Wespen", null, subtree, null, null, false, null, null, null, null);
525
        Assert.assertEquals("AND search : Expecting no entity", 0, pager.getCount().intValue());
526

    
527
        pager = taxonService.findByDescriptionElementFullText(TextData.class, "\"Pflanzenart aus der Gattung der Tannen\"", null, subtree, null, null, false, null, null, null, null);
528
        Assert.assertEquals("Phrase search : Expecting one entity", 1, pager.getCount().intValue());
529

    
530
        pager = taxonService.findByDescriptionElementFullText(TextData.class, "\"Pflanzenart aus der Gattung der Wespen\"", null, subtree, null, null, false, null, null, null, null);
531
        Assert.assertEquals("Phrase search : Expecting one entity", 0, pager.getCount().intValue());
532

    
533
        logger.info("testFindByDescriptionElementFullText_MultipleWords() duration: " + (System.currentTimeMillis() - start) + "ms");
534

    
535
    }
536

    
537

    
538
    @SuppressWarnings("rawtypes")
539
    @Test
540
    @DataSet(loadStrategy=CleanSweepInsertLoadStrategy.class)
541
    public final void testFindByDescriptionElementFullText_modify_DescriptionElement() throws IOException, LuceneParseException {
542

    
543
        refreshLuceneIndex();
544
        TaxonNode subtree = null;
545

    
546
        //
547
        // modify the DescriptionElement
548
        Pager<SearchResult<TaxonBase>> pager = taxonService.findByDescriptionElementFullText(TextData.class, "Balsam-Tanne", null, subtree, null, Arrays.asList(new Language[]{Language.GERMAN(), Language.RUSSIAN()}), false, null, null, null, null);
549
        Assert.assertTrue("Search did not return any results", pager.getRecords().size() > 0);
550
        Assert.assertTrue("Expecting only one doc", pager.getRecords().get(0).getDocs().size() == 1);
551
        Document indexDocument = pager.getRecords().get(0).getDocs().iterator().next();
552
        String[] descriptionElementUuidStr = indexDocument.getValues("uuid");
553
        String[] inDescriptionUuidStr = indexDocument.getValues("inDescription.uuid");
554
        // is only one uuid!
555
        DescriptionElementBase textData = descriptionElementService.find(UUID.fromString(descriptionElementUuidStr[0]));
556

    
557
        ((TextData)textData).removeText(Language.GERMAN());
558
        ((TextData)textData).putText(Language.SPANISH_CASTILIAN(), "abeto bals"+UTF8.SMALL_A_ACUTE+"mico");
559

    
560
        descriptionElementService.save(textData);
561
        commitAndStartNewTransaction(null);
562
//        printDataSet(System.out, new String[] {
563
//                "DESCRIPTIONELEMENTBASE", "LANGUAGESTRING", "DESCRIPTIONELEMENTBASE_LANGUAGESTRING" }
564
//        );
565

    
566
        //
567
        pager = taxonService.findByDescriptionElementFullText(TextData.class, "Balsam-Tanne", null, subtree, null, Arrays.asList(new Language[]{Language.GERMAN(), Language.RUSSIAN()}), false, null, null, null, null);
568
        Assert.assertEquals("The german 'Balsam-Tanne' TextData should no longer be indexed", 0, pager.getCount().intValue());
569
        pager = taxonService.findByDescriptionElementFullText(TextData.class, "abeto", null, subtree, null, Arrays.asList(new Language[]{Language.SPANISH_CASTILIAN()}), false, null, null, null, null);
570
        Assert.assertEquals("expecting to find the SPANISH_CASTILIAN 'abeto bals"+UTF8.SMALL_A_ACUTE+"mico'", 1, pager.getCount().intValue());
571
        pager = taxonService.findByDescriptionElementFullText(TextData.class, "bals"+UTF8.SMALL_A_ACUTE+"mico", null, subtree, null, null, false, null, null, null, null);
572
        Assert.assertEquals("expecting to find the SPANISH_CASTILIAN 'abeto bals"+UTF8.SMALL_A_ACUTE+"mico'", 1, pager.getCount().intValue());
573

    
574
        //
575
        // modify the DescriptionElement via the Description object
576
        DescriptionBase<?> description = descriptionService.find(UUID.fromString(inDescriptionUuidStr[0]));
577
        Set<DescriptionElementBase> elements = description.getElements();
578
        for( DescriptionElementBase elm : elements){
579
            if(elm.getUuid().toString().equals(descriptionElementUuidStr[0])){
580
                ((TextData)elm).removeText(Language.SPANISH_CASTILIAN());
581
                ((TextData)elm).putText(Language.POLISH(), "Jod"+UTF8.POLISH_L+"a balsamiczna");
582
            }
583
        }
584
        descriptionService.saveOrUpdate(description);
585
        commitAndStartNewTransaction(null);
586
        pager = taxonService.findByDescriptionElementFullText(TextData.class, "abeto", null, subtree, null, Arrays.asList(new Language[]{Language.SPANISH_CASTILIAN()}), false, null, null, null, null);
587
        Assert.assertEquals("The spanish 'abeto bals"+UTF8.SMALL_A_ACUTE+"mico' TextData should no longer be indexed", 0, pager.getCount().intValue());
588
        pager = taxonService.findByDescriptionElementFullText(TextData.class, "balsamiczna", null, subtree, null, Arrays.asList(new Language[]{Language.POLISH()}), false, null, null, null, null);
589
        Assert.assertEquals("expecting to find the POLISH 'Jod"+UTF8.POLISH_L+"a balsamiczna'", 1, pager.getCount().intValue());
590
    }
591

    
592
    @SuppressWarnings("rawtypes")
593
    @Test
594
    @DataSet(loadStrategy=CleanSweepInsertLoadStrategy.class)
595
    public final void testFindByDescriptionElementFullText_modify_Taxon() throws IOException, LuceneParseException {
596

    
597
        refreshLuceneIndex();
598
        TaxonNode subtree = null;
599

    
600
        Taxon t_abies_balsamea = (Taxon)taxonService.find(ABIES_BALSAMEA_UUID);
601
        TaxonDescription d_abies_balsamea = (TaxonDescription)descriptionService.find(DESC_ABIES_BALSAMEA_UUID);
602

    
603
        Pager<SearchResult<TaxonBase>> pager = taxonService.findByDescriptionElementFullText(TextData.class, "Balsam-Tanne",
604
                null, subtree, null, Arrays.asList(new Language[]{Language.GERMAN()}), false, null, null, null, null);
605
        Assert.assertEquals("expecting to find the GERMAN 'Balsam-Tanne'", 1, pager.getCount().intValue());
606

    
607
        // exchange the Taxon with another one via the Taxon object
608
        // 1.) remove existing description:
609
        t_abies_balsamea.removeDescription(d_abies_balsamea);
610

    
611
        taxonService.saveOrUpdate(t_abies_balsamea);
612
        commitAndStartNewTransaction(null);
613

    
614
        t_abies_balsamea = (Taxon)taxonService.find(t_abies_balsamea.getUuid());
615

    
616
        pager = taxonService.findByDescriptionElementFullText(TextData.class, "Balsam-Tanne",
617
                null, subtree, null, Arrays.asList(new Language[]{Language.GERMAN()}), false, null, null, null, null);
618
        Assert.assertEquals("'Balsam-Tanne' should no longer be found", 0, pager.getCount().intValue());
619

    
620
        // 2.) create new description and add to taxon:
621
        TaxonDescription d_abies_balsamea_new = TaxonDescription.NewInstance();
622
        d_abies_balsamea_new
623
                .addElement(TextData
624
                        .NewInstance(
625
                                "Die Balsamtanne ist mit bis zu 30 m Höhe ein mittelgro"+UTF8.SHARP_S+"er Baum und kann bis zu 200 Jahre alt werden",
626
                                Language.GERMAN(), null));
627
        t_abies_balsamea.addDescription(d_abies_balsamea_new);
628
        // set authorshipCache to null to avoid validation exception,
629
        // this is maybe not needed in future,  see ticket #3344
630
        IBotanicalName abies_balsamea = CdmBase.deproxy(t_abies_balsamea.getName(), TaxonName.class);
631
        abies_balsamea.setAuthorshipCache(null);
632
        printDataSet(System.err, new String[] {"LANGUAGESTRING_AUD"});
633
        taxonService.saveOrUpdate(t_abies_balsamea);
634
        commitAndStartNewTransaction(null);
635

    
636
//        printDataSet(System.out, new String[] {
637
//                "DESCRIPTIONBASE"
638
//        });
639

    
640
        pager = taxonService.findByDescriptionElementFullText(TextData.class, "mittelgro"+UTF8.SHARP_S+"er Baum",
641
                null, subtree, null, Arrays.asList(new Language[]{Language.GERMAN()}), false, null, null, null, null);
642
        Assert.assertEquals("the taxon should be found via the new Description", 1, pager.getCount().intValue());
643
    }
644

    
645
    @SuppressWarnings("rawtypes")
646
    @Test
647
    @DataSet
648
    public final void testFindByDescriptionElementFullText_modify_Classification() throws IOException, LuceneParseException {
649

    
650
        refreshLuceneIndex();
651
        TaxonNode subtree = null;
652

    
653
        // put taxon into other classification, new taxon node
654
        Classification classification = classificationService.find(CLASSIFICATION_UUID);
655
        Classification alternateClassification = classificationService.find(CLASSIFICATION_ALT_UUID);
656

    
657
        // TODO: why is the test failing when the childNode is already retrieved here, and not after the following four lines?
658
        //TaxonNode childNode = classification.getChildNodes().iterator().next();
659

    
660
        Pager<SearchResult<TaxonBase>> pager = taxonService.findByDescriptionElementFullText(TextData.class, "Balsam-Tanne", null, subtree, null, Arrays.asList(new Language[]{Language.GERMAN()}), false, null, null, null, null);
661
        Assert.assertEquals("expecting to find the GERMAN 'Balsam-Tanne' even if filtering by classification", 1, pager.getCount().intValue());
662
        pager = taxonService.findByDescriptionElementFullText(TextData.class, "Balsam-Tanne", alternateClassification, subtree, null, Arrays.asList(new Language[]{Language.GERMAN()}), false, null, null, null, null);
663
        Assert.assertEquals("GERMAN 'Balsam-Tanne' should NOT be found in other classification", 0, pager.getCount().intValue());
664

    
665
        // check for the right taxon node
666
        TaxonNode childNode = classification.getChildNodes().iterator().next();
667
        Assert.assertEquals("expecting Abies balsamea sec.", childNode.getTaxon().getUuid(), ABIES_BALSAMEA_UUID);
668
        Assert.assertEquals("expecting default classification", childNode.getClassification().getUuid(), CLASSIFICATION_UUID);
669

    
670
        // moving the taxon around, the rootnode is only a proxy
671
        alternateClassification.setRootNode(HibernateProxyHelper.deproxy(alternateClassification.getRootNode(), TaxonNode.class));
672
        alternateClassification.addChildNode(childNode, null, null);
673

    
674
        classificationService.saveOrUpdate(alternateClassification);
675
        commitAndStartNewTransaction(null);
676

    
677
//        printDataSet(System.out, new String[] {
678
//            "TAXONBASE", "TAXONNODE", "CLASSIFICATION"
679
//        });
680

    
681
        // reload classification
682
        classification = classificationService.find(CLASSIFICATION_UUID);
683
        pager = taxonService.findByDescriptionElementFullText(TextData.class, "Balsam-Tanne",
684
                alternateClassification, subtree, null, Arrays.asList(new Language[]{Language.GERMAN()}), false, null, null, null, null);
685
        Assert.assertEquals("GERMAN 'Balsam-Tanne' should now be found in other classification", 1, pager.getCount().intValue());
686

    
687
        classification.getChildNodes().clear();
688
        classificationService.saveOrUpdate(classification);
689
        commitAndStartNewTransaction(null);
690

    
691
        pager = taxonService.findByDescriptionElementFullText(TextData.class, "Balsam-Tanne",
692
                classification, subtree, null, Arrays.asList(new Language[]{Language.GERMAN()}), false, null, null, null, null);
693
        Assert.assertEquals("Now the GERMAN 'Balsam-Tanne' should NOT be found in original classification", 0, pager.getCount().intValue());
694

    
695
    }
696

    
697
    @SuppressWarnings("rawtypes")
698
    @Test
699
    @DataSet
700
    public final void testFindByDescriptionElementFullText_CategoricalData() throws IOException, LuceneParseException {
701

    
702
        TaxonNode subtree = null;
703
        // add CategoricalData
704
        DescriptionBase d_abies_balsamea = descriptionService.find(DESC_ABIES_BALSAMEA_UUID);
705
        // Categorical data
706
        CategoricalData cdata = CategoricalData.NewInstance();
707
        cdata.setFeature(Feature.DESCRIPTION());
708
        State state = State.NewInstance("green", "green", "gn");
709

    
710
        StateData statedata = StateData.NewInstance(state);
711
        statedata.putModifyingText(Language.ENGLISH(), "always, even during winter");
712
        cdata.addStateData(statedata);
713
        d_abies_balsamea.addElement(cdata);
714

    
715
        UUID termUUID = termService.save(state).getUuid();
716
        descriptionService.save(d_abies_balsamea);
717

    
718
        commitAndStartNewTransaction(null);
719

    
720
//        printDataSet(System.out, new String[] {
721
//                 "STATEDATA", "STATEDATA_DEFINEDTERMBASE", "STATEDATA_LANGUAGESTRING", "LANGUAGESTRING"});
722

    
723
        refreshLuceneIndex();
724

    
725
        Pager<SearchResult<TaxonBase>> pager = taxonService.findByDescriptionElementFullText(CategoricalData.class, "green", null, subtree, null, null, false, null, null, null, null);
726
        Assert.assertEquals("Expecting one entity", 1, pager.getCount().intValue());
727
        Assert.assertEquals("Abies balsamea sec. Kohlbecker, A., Testcase standart views, 2013", pager.getRecords().get(0).getEntity().getTitleCache());
728
        Assert.assertTrue("Expecting only one doc", pager.getRecords().get(0).getDocs().size() == 1);
729
        Assert.assertEquals("Abies balsamea sec. Kohlbecker, A., Testcase standart views, 2013", pager.getRecords().get(0).getDocs().iterator().next().get("inDescription.taxon.titleCache"));
730

    
731

    
732
        //TODO modify the StateData
733
        TaxonBase taxon = pager.getRecords().get(0).getEntity();
734

    
735
        String newName = "Quercus robur";
736
        taxon.setTitleCache(newName + " sec. ", true);
737

    
738
        taxonService.saveOrUpdate(taxon);
739
        commitAndStartNewTransaction(null);
740

    
741
        taxon = taxonService.find(taxon.getUuid());
742
        Assert.assertEquals(newName + " sec. ", taxon.getTitleCache());
743
        DefinedTermBase term = termService.find(termUUID);
744

    
745
        termService.delete(term);
746

    
747
    }
748

    
749
    @SuppressWarnings("rawtypes")
750
    @Test
751
    @DataSet
752
    public final void testFindByDescriptionElementFullText_Highlighting() throws IOException, LuceneParseException {
753

    
754
        refreshLuceneIndex();
755
        TaxonNode subtree = null;
756

    
757
        Pager<SearchResult<TaxonBase>> pager = taxonService.findByDescriptionElementFullText(TextData.class, "Abies", null, subtree, null, null, true, null, null, null, null);
758
        Assert.assertEquals("Expecting one entity when searching for any TextData", 1, pager.getCount().intValue());
759
        SearchResult<TaxonBase> searchResult = pager.getRecords().get(0);
760
        Assert.assertTrue("the map of highlighted fragments should contain at least one item", searchResult.getFieldHighlightMap().size() > 0);
761
        String[] fragments = searchResult.getFieldHighlightMap().values().iterator().next();
762
        Assert.assertTrue("first fragments should contains serch term", fragments[0].contains("<B>Abies</B>"));
763

    
764
        pager = taxonService.findByDescriptionElementFullText(TextData.class, "Pflanzenart Tannen", null, subtree, null, null, true, null, null, null, null);
765
        searchResult = pager.getRecords().get(0);
766
        Assert.assertTrue("Phrase search : Expecting at least one item in highlighted fragments", searchResult.getFieldHighlightMap().size() > 0);
767
        fragments = searchResult.getFieldHighlightMap().values().iterator().next();
768
        Assert.assertTrue("first fragments should contains serch term", fragments[0].contains("<B>Pflanzenart</B>") || fragments[0].contains("<B>Tannen</B>"));
769

    
770
        pager = taxonService.findByDescriptionElementFullText(TextData.class, "+Pflanzenart +Tannen", null, subtree, null, null, true, null, null, null, null);
771
        searchResult = pager.getRecords().get(0);
772
        Assert.assertTrue("Phrase search : Expecting at least one item in highlighted fragments", searchResult.getFieldHighlightMap().size() > 0);
773
        fragments = searchResult.getFieldHighlightMap().values().iterator().next();
774
        Assert.assertTrue("first fragments should contains serch term", fragments[0].contains("<B>Pflanzenart</B>") && fragments[0].contains("<B>Tannen</B>"));
775

    
776
        pager = taxonService.findByDescriptionElementFullText(TextData.class, "\"Pflanzenart aus der Gattung der Tannen\"", null, subtree, null, null, true, null, null, null, null);
777
        searchResult = pager.getRecords().get(0);
778
        Assert.assertTrue("Phrase search : Expecting at least one item in highlighted fragments", searchResult.getFieldHighlightMap().size() > 0);
779
        fragments = searchResult.getFieldHighlightMap().values().iterator().next();
780
        Assert.assertTrue("first fragments should contains serch term", fragments[0].contains("<B>Pflanzenart</B> <B>aus</B> <B>der</B> <B>Gattung</B> <B>der</B> <B>Tannen</B>"));
781

    
782
        pager = taxonService.findByDescriptionElementFullText(TextData.class, "Gatt*", null, subtree, null, null, true, null, null, null, null);
783
        searchResult = pager.getRecords().get(0);
784
        Assert.assertTrue("Wildcard search : Expecting at least one item in highlighted fragments", searchResult.getFieldHighlightMap().size() > 0);
785
        fragments = searchResult.getFieldHighlightMap().values().iterator().next();
786
        Assert.assertTrue("first fragments should contains serch term", fragments[0].contains("<B>Gatt"));
787
    }
788

    
789

    
790
    @Test
791
    @DataSet(loadStrategy=CleanSweepInsertLoadStrategy.class)
792
    public final void testFindByFullText() throws IOException, LuceneParseException {
793

    
794
        refreshLuceneIndex();
795

    
796
        classificationService.find(CLASSIFICATION_UUID);
797
        TaxonNode subtree = null;
798

    
799
        boolean NO_UNPUBLISHED = false;
800

    
801
        Pager<SearchResult<TaxonBase>> pager = taxonService.findByFullText(null, "Abies", null, subtree, includeUnpublished, null, true, null, null, null, null); // --> 7
802
//        logFreeTextSearchResults(pager, Level.DEBUG, null);
803
        Assert.assertEquals("Expecting 8 entities", 8, pager.getCount().intValue());
804

    
805
        //subtree
806
        subtree = nodeService.find(ROOTNODE_CLASSIFICATION_5000);
807
        pager = taxonService.findByFullText(null, "Abies", null, subtree, includeUnpublished, null, true, null, null, null, null); // --> 0
808
        Assert.assertEquals("Expecting 2 entities", 2, pager.getCount().intValue());
809
        subtree = null;
810

    
811
        pager = taxonService.findByFullText(null, "Abies", null, subtree, NO_UNPUBLISHED, null, true, null, null, null, null); // --> 7
812
//        logFreeTextSearchResults(pager, Level.DEBUG, null);
813
        Assert.assertEquals("Expecting 6 entities", 6, pager.getCount().intValue());
814
        Synonym abiesSubalpina = (Synonym)taxonService.find(ABIES_SUBALPINA_UUID);
815

    
816
        //accepted published, syn not published
817
        abiesSubalpina.getAcceptedTaxon().setPublish(true);
818
        commitAndStartNewTransaction();
819
        pager = taxonService.findByFullText(null, "Abies", null, subtree, NO_UNPUBLISHED, null, true, null, null, null, null); // --> 7
820
        Assert.assertEquals("Expecting 7 entities", 7, pager.getCount().intValue());
821

    
822
        //accepted published, syn published
823
        abiesSubalpina = (Synonym)taxonService.find(abiesSubalpina.getUuid());
824
        abiesSubalpina.setPublish(true);
825
        commitAndStartNewTransaction();
826
        pager = taxonService.findByFullText(null, "Abies", null, subtree, NO_UNPUBLISHED, null, true, null, null, null, null); // --> 7
827
        Assert.assertEquals("Expecting 8 entities", 8, pager.getCount().intValue());
828

    
829
        //accepted not published, syn published
830
        abiesSubalpina = (Synonym)taxonService.find(abiesSubalpina.getUuid());
831
        abiesSubalpina.getAcceptedTaxon().setPublish(false);
832
        commitAndStartNewTransaction();
833
        pager = taxonService.findByFullText(null, "Abies", null, subtree, NO_UNPUBLISHED, null, true, null, null, null, null); // --> 7
834
        Assert.assertEquals("Expecting 6 entities. Synonym and accepted should not be found, though synonym is published",
835
                6, pager.getCount().intValue());
836

    
837
        pager = taxonService.findByFullText(Taxon.class, "Abies", null, subtree, includeUnpublished, null, true, null, null, null, null); // --> 6
838
        Assert.assertEquals("Expecting 7 entities", 7, pager.getCount().intValue());
839

    
840
        pager = taxonService.findByFullText(Synonym.class, "Abies", null, subtree, includeUnpublished, null, true, null, null, null, null); // --> 1
841
        Assert.assertEquals("Expecting 1 entity", 1, pager.getCount().intValue());
842
        pager = taxonService.findByFullText(Synonym.class, "Abies", null, subtree, NO_UNPUBLISHED, null, true, null, null, null, null); // --> 1
843
        Assert.assertEquals("Expecting 0 entity", 0, pager.getCount().intValue());
844

    
845
        pager = taxonService.findByFullText(TaxonBase.class, "sec", null, subtree, includeUnpublished, null, true, null, null, null, null); // --> 7
846
        Assert.assertEquals("Expecting 8 entities", 9, pager.getCount().intValue());
847

    
848
        pager = taxonService.findByFullText(null, "genus", null, subtree, includeUnpublished, null, true, null, null, null, null); // --> 1
849
        Assert.assertEquals("Expecting 1 entity", 1, pager.getCount().intValue());
850

    
851
        pager = taxonService.findByFullText(Taxon.class, "subalpina", null, subtree, includeUnpublished, null, true, null, null, null, null); // --> 0
852
        Assert.assertEquals("Expecting 0 entities", 0, pager.getCount().intValue());
853

    
854

    
855
        // synonym in classification ???
856
    }
857

    
858
    @Test
859
    @DataSet
860
    public final void testPrepareByAreaSearch() throws IOException, LuceneParseException {
861

    
862
        List<PresenceAbsenceTerm> statusFilter = new ArrayList<>();
863
        List<NamedArea> areaFilter = new ArrayList<>();
864
        areaFilter.add(germany);
865
        areaFilter.add(canada);
866
        areaFilter.add(russia);
867

    
868
        Pager<SearchResult<TaxonBase>> pager = taxonService.findByDistribution(areaFilter, statusFilter, null, null, 20, 0, null, null);
869
        Assert.assertEquals("Expecting 2 entities", Integer.valueOf(2), Integer.valueOf(pager.getRecords().size()));
870

    
871
    }
872

    
873
    @Test
874
    @DataSet
875
    public final void testFindTaxaAndNamesByFullText_synonymClassificationSubtree() throws IOException, LuceneParseException, LuceneMultiSearchException {
876

    
877
        refreshLuceneIndex();
878
        Classification classification = null;
879
        TaxonNode subtree = null;
880

    
881
        //
882
        Pager<SearchResult<TaxonBase>> pager;
883
        EnumSet<TaxaAndNamesSearchMode> taxaAndSynonyms = EnumSet.of(TaxaAndNamesSearchMode.doTaxa, TaxaAndNamesSearchMode.doSynonyms, TaxaAndNamesSearchMode.includeUnpublished);
884
        pager = taxonService.findTaxaAndNamesByFullText(
885
                taxaAndSynonyms, "Abies", classification, subtree, null, null, null, true, null, null, null, null);
886
        Assert.assertEquals("doTaxa & doSynonyms & unpublished", 8, pager.getCount().intValue());
887

    
888
        EnumSet<TaxaAndNamesSearchMode> taxaOnly = EnumSet.of(TaxaAndNamesSearchMode.doTaxa, TaxaAndNamesSearchMode.includeUnpublished);
889

    
890
        //classification
891
        classification = classificationService.find(CLASSIFICATION_UUID);
892
        pager = taxonService.findTaxaAndNamesByFullText(
893
                taxaAndSynonyms, "Abies", classification, subtree, null, null, null, true, null, null, null, null);
894
        Assert.assertEquals("doTaxa & doSynonyms & unpublished", 2, pager.getCount().intValue());
895
            //taxa only
896
        pager = taxonService.findTaxaAndNamesByFullText(
897
                taxaOnly, "Abies", classification, subtree, null, null, null, true, null, null, null, null);
898
        Assert.assertEquals("doTaxa & unpublished", 1, pager.getCount().intValue());
899
            //synonyms only
900
        pager = taxonService.findTaxaAndNamesByFullText(
901
                taxaOnly, "Abies", classification, subtree, null, null, null, true, null, null, null, null);
902
        Assert.assertEquals("doSynonyms & unpublished", 1, pager.getCount().intValue());
903

    
904
        classification = null;
905

    
906
        //subtree
907
       subtree = nodeService.find(ROOTNODE_CLASSIFICATION_5000);
908
       pager = taxonService.findTaxaAndNamesByFullText(
909
               taxaAndSynonyms, "Abies", classification, subtree, null, null, null, true, null, null, null, null);
910
       Assert.assertEquals("doTaxa & doSynonyms & unpublished", 2, pager.getCount().intValue());
911
         //taxa only
912
       pager = taxonService.findTaxaAndNamesByFullText(
913
               taxaOnly, "Abies", classification, subtree, null, null, null, true, null, null, null, null);
914
       Assert.assertEquals("doTaxa & unpublished", 1, pager.getCount().intValue());
915
       subtree = null;
916

    
917
    }
918

    
919
    @Test
920
    @DataSet
921
    public final void testFindTaxaAndNamesByFullText() throws IOException, LuceneParseException, LuceneMultiSearchException {
922

    
923
        refreshLuceneIndex();
924
        TaxonNode subtree = null;
925

    
926
        Classification alternateClassification = classificationService.find(CLASSIFICATION_ALT_UUID);
927
        Synonym abiesSubalpina = (Synonym)taxonService.find(ABIES_SUBALPINA_UUID);
928

    
929
        Pager<SearchResult<TaxonBase>> pager;
930
        EnumSet<TaxaAndNamesSearchMode> modes = EnumSet.of(TaxaAndNamesSearchMode.doTaxa, TaxaAndNamesSearchMode.doSynonyms, TaxaAndNamesSearchMode.includeUnpublished);
931
        pager = taxonService.findTaxaAndNamesByFullText(
932
                modes, "Abies", null, subtree, null, null, null, true, null, null, null, null);
933
        Assert.assertEquals("doTaxa & doSynonyms & unpublished", 8, pager.getCount().intValue());
934
//      logPagerRecords(pager, Level.DEBUG);
935

    
936
         //unpublished
937
        pager = taxonService.findTaxaAndNamesByFullText(TaxaAndNamesSearchMode.taxaAndSynonyms(),
938
                "Abies", null, subtree, null, null, null, true, null, null, null, null);
939
        Assert.assertEquals("doTaxa & doSynonyms, published only", 6, pager.getCount().intValue());
940

    
941
        //accepted published, syn not published
942
        abiesSubalpina.getAcceptedTaxon().setPublish(true);
943
        commitAndStartNewTransaction();
944
        pager = taxonService.findTaxaAndNamesByFullText(TaxaAndNamesSearchMode.taxaAndSynonyms(),
945
                "Abies", null, subtree, null, null, null, true, null, null, null, null);
946
        Assert.assertEquals("doTaxa & doSynonyms, accepted published", 7, pager.getCount().intValue());
947

    
948
        //accepted published, syn published
949
        abiesSubalpina = (Synonym)taxonService.find(abiesSubalpina.getUuid());
950
        abiesSubalpina.setPublish(true);
951
        commitAndStartNewTransaction();
952
        pager = taxonService.findTaxaAndNamesByFullText(TaxaAndNamesSearchMode.taxaAndSynonyms(),
953
                "Abies", null, subtree, null, null, null, true, null, null, null, null);
954
        Assert.assertEquals("Expecting 8 entities", 8, pager.getCount().intValue());
955

    
956
        //accepted not published, syn published
957
        abiesSubalpina = (Synonym)taxonService.find(abiesSubalpina.getUuid());
958
        abiesSubalpina.getAcceptedTaxon().setPublish(false);
959
        commitAndStartNewTransaction();
960
        pager = taxonService.findTaxaAndNamesByFullText(TaxaAndNamesSearchMode.taxaAndSynonyms(),
961
                "Abies", null, subtree, null, null, null, true, null, null, null, null);
962
        Assert.assertEquals("Expecting 6 entities. Synonym and accepted should not be found, though synonym is published",
963
                6, pager.getCount().intValue());
964

    
965
        EnumSet<TaxaAndNamesSearchMode> searchMode = EnumSet.allOf(TaxaAndNamesSearchMode.class);
966
        pager = taxonService.findTaxaAndNamesByFullText(
967
                searchMode, "Abies", null, subtree, null, null, null, true, null, null, null, null);
968
//        logPagerRecords(pager, Level.DEBUG);
969
        Assert.assertEquals("all search modes", 8, pager.getCount().intValue());
970
        searchMode.remove(TaxaAndNamesSearchMode.includeUnpublished);
971
        pager = taxonService.findTaxaAndNamesByFullText(
972
                searchMode, "Abies", null, subtree, null, null, null, true, null, null, null, null);
973
        Assert.assertEquals("all search modes except unpublished", 6, pager.getCount().intValue());
974

    
975
        pager = taxonService.findTaxaAndNamesByFullText(EnumSet.allOf(TaxaAndNamesSearchMode.class),
976
                "Abies", alternateClassification, subtree, null, null, null, true, null, null, null, null);
977
//        logPagerRecords(pager, Level.DEBUG);
978
        Assert.assertEquals("all search modes, filtered by alternateClassification", 1, pager.getCount().intValue());
979

    
980
        pager = taxonService.findTaxaAndNamesByFullText(
981
                EnumSet.of(TaxaAndNamesSearchMode.doSynonyms, TaxaAndNamesSearchMode.includeUnpublished),
982
                "Abies", null, subtree, null, null, null, true, null, null, null, null);
983
        Assert.assertEquals("Expecting 2 entity", 2, pager.getCount().intValue());
984
        Set<UUID> uuids = getTaxonUuidSet(pager);
985
        Assert.assertTrue("The real synonym should be contained", uuids.contains(ABIES_SUBALPINA_UUID));
986
        Assert.assertTrue("The pro parte synonym should be contained",uuids.contains(ABIES_LASIOCARPA_UUID));
987
        //without published
988
        pager = taxonService.findTaxaAndNamesByFullText(EnumSet.of(TaxaAndNamesSearchMode.doSynonyms),
989
                "Abies", null, subtree, null, null, null, true, null, null, null, null);
990
        Assert.assertEquals("Expecting 0 entities", 0, pager.getCount().intValue());
991

    
992

    
993
        pager = taxonService.findTaxaAndNamesByFullText(
994
                EnumSet.of(TaxaAndNamesSearchMode.doTaxaByCommonNames, TaxaAndNamesSearchMode.includeUnpublished),
995
                "Abies", null, subtree, null, null, null, true, null, null, null, null);
996
        Assert.assertEquals("Expecting 0 entity", 0, pager.getCount().intValue());
997

    
998
        pager = taxonService.findTaxaAndNamesByFullText(
999
                EnumSet.of(TaxaAndNamesSearchMode.doTaxaByCommonNames, TaxaAndNamesSearchMode.includeUnpublished),
1000
                "Tanne", null, subtree, null, null, null, true, null, null, null, null);
1001
        Assert.assertEquals("Expecting 1 entity", 1, pager.getRecords().size());
1002
        Assert.assertEquals("Expecting 1 entity", 1, pager.getCount().intValue());
1003
        pager = taxonService.findTaxaAndNamesByFullText(
1004
                EnumSet.of(TaxaAndNamesSearchMode.doTaxaByCommonNames),
1005
                "Tanne", null, subtree, null, null, null, true, null, null, null, null);
1006
        Assert.assertEquals("Expecting 0 entity", 0, pager.getRecords().size());
1007

    
1008
        //misapplied names
1009
        pager = taxonService.findTaxaAndNamesByFullText(
1010
                EnumSet.of(TaxaAndNamesSearchMode.doMisappliedNames, TaxaAndNamesSearchMode.includeUnpublished),
1011
                "kawakamii", (Classification)null, subtree, null, null, null, true, null, null, null, null);
1012
        logFreeTextSearchResults(pager, Level.DEBUG, null);
1013
        Assert.assertEquals("Expecting 1 entity", 1, pager.getCount().intValue());
1014
        //unpublish accepted taxon
1015
        pager = taxonService.findTaxaAndNamesByFullText(
1016
                EnumSet.of(TaxaAndNamesSearchMode.doMisappliedNames),
1017
                "kawakamii", (Classification)null, subtree, null, null, null, true, null, null, null, null);
1018
        Assert.assertEquals("Expecting 0 entities", 0, pager.getCount().intValue());
1019
        //published accepted taxon/misapplied name
1020
        Taxon abiesBalsamea = (Taxon)taxonService.find(ABIES_BALSAMEA_UUID);
1021
        abiesBalsamea.setPublish(true);
1022
        commitAndStartNewTransaction();
1023
        pager = taxonService.findTaxaAndNamesByFullText(
1024
                EnumSet.of(TaxaAndNamesSearchMode.doMisappliedNames),
1025
                "kawakamii", (Classification)null, subtree, null, null, null, true, null, null, null, null);
1026
        Assert.assertEquals("Expecting 1 entities", 1, pager.getCount().intValue());
1027
        //unpublished misapplied name
1028
        Taxon misapplied = (Taxon)taxonService.find(DESC_ABIES_KAWAKAMII_SEC_KOMAROV_UUID);
1029
        misapplied.setPublish(false);
1030
        commitAndStartNewTransaction();
1031
        pager = taxonService.findTaxaAndNamesByFullText(
1032
                EnumSet.of(TaxaAndNamesSearchMode.doMisappliedNames),
1033
                "kawakamii", (Classification)null, subtree, null, null, null, true, null, null, null, null);
1034
        Assert.assertEquals("Expecting 0 entities", 0, pager.getCount().intValue());
1035

    
1036
    }
1037

    
1038
    @Test
1039
    @DataSet
1040
    public final void testFindTaxaAndNamesByFullText_wildcard() throws IOException, LuceneParseException, LuceneMultiSearchException {
1041

    
1042
        refreshLuceneIndex();
1043
        TaxonNode subtree = null;
1044

    
1045
        Pager<SearchResult<TaxonBase>> pager;
1046
         pager = taxonService.findTaxaAndNamesByFullText(TaxaAndNamesSearchMode.taxaAndSynonyms(),
1047
                "Abi*", null, subtree, null, null, null, true, null, null, null, null);
1048
//      logFreeTextSearchResults(pager, Level.DEBUG, null);
1049
        Assert.assertEquals("doTaxa & doSynonyms published only", 6, pager.getCount().intValue());
1050
        pager = taxonService.findTaxaAndNamesByFullText(TaxaAndNamesSearchMode.taxaAndSynonyms(),
1051
                "*bies", null, subtree, null, null, null, true, null, null, null, null);
1052
        Assert.assertEquals("doTaxa & doSynonyms, published only", 6, pager.getCount().intValue());
1053
        // logFreeTextSearchResults(pager, Level.ERROR, null);
1054
        pager = taxonService.findTaxaAndNamesByFullText(TaxaAndNamesSearchMode.taxaAndSynonyms(),
1055
                "?bies", null, subtree, null, null, null, true, null, null, null, null);
1056
        Assert.assertEquals("doTaxa & doSynonyms, published only", 6, pager.getCount().intValue());
1057
        // logFreeTextSearchResults(pager, Level.ERROR, null);
1058
        pager = taxonService.findTaxaAndNamesByFullText(TaxaAndNamesSearchMode.taxaAndSynonyms(),
1059
                "*", null, subtree, null, null, null, true, null, null, null, null);
1060
        Assert.assertEquals("doTaxa & doSynonyms, published only", 7, pager.getCount().intValue());
1061
    }
1062

    
1063
    @Test
1064
    @DataSet
1065
    // @Ignore // FIXME: fails due  org.apache.lucene.queryparser.classic.ParseException: Cannot parse 'relatedFrom.titleCache:()': Encountered " ")" ") "" at line 1, column 24.
1066
    public final void testFindTaxaAndNamesByFullText_empty_querString() throws IOException, LuceneParseException, LuceneMultiSearchException {
1067

    
1068
        refreshLuceneIndex();
1069
        TaxonNode subtree = null;
1070

    
1071
        Pager<SearchResult<TaxonBase>> pager;
1072
        pager = taxonService.findTaxaAndNamesByFullText(EnumSet.of(TaxaAndNamesSearchMode.doTaxa),
1073
                "", null, subtree, null, null, null, true, null, null, null, null);
1074
        Assert.assertEquals("doTaxa, published only", 7, pager.getCount().intValue());
1075

    
1076
        pager = taxonService.findTaxaAndNamesByFullText(TaxaAndNamesSearchMode.taxaAndSynonyms(),
1077
                "", null, subtree, null, null, null, true, null, null, null, null);
1078
        Assert.assertEquals("doTaxa & doSynonyms, published only", 7, pager.getCount().intValue());
1079

    
1080
        pager = taxonService.findTaxaAndNamesByFullText(EnumSet.of(TaxaAndNamesSearchMode.doTaxa, TaxaAndNamesSearchMode.doMisappliedNames),
1081
                null, null, subtree, null, null, null, true, null, null, null, null);
1082
        Assert.assertEquals("doTaxa & doMisappliedNames published only", 7, pager.getCount().intValue());
1083

    
1084
        pager = taxonService.findTaxaAndNamesByFullText(EnumSet.of(TaxaAndNamesSearchMode.doTaxa, TaxaAndNamesSearchMode.doMisappliedNames, TaxaAndNamesSearchMode.doTaxaByCommonNames),
1085
                null, null, subtree, null, null, null, true, null, null, null, null);
1086
        Assert.assertEquals("doTaxa & doMisappliedNames & doTaxaByCommonNames , published only", 7, pager.getCount().intValue());
1087
        // logFreeTextSearchResults(pager, Level.ERROR, null);
1088
    }
1089

    
1090
    @Test
1091
    @DataSet
1092
    //test for https://dev.e-taxonomy.eu/redmine/issues/7486
1093
    public final void testFindTaxaAndNamesByFullText_synonymsAndMisapplied_7486() throws IOException, LuceneParseException, LuceneMultiSearchException {
1094

    
1095
        refreshLuceneIndex();
1096
        TaxonNode subtree = null;
1097

    
1098
        //misapplied names
1099
        Pager<SearchResult<TaxonBase>> pager = taxonService.findTaxaAndNamesByFullText(
1100
                EnumSet.of(TaxaAndNamesSearchMode.doSynonyms, TaxaAndNamesSearchMode.doMisappliedNames, TaxaAndNamesSearchMode.includeUnpublished),
1101
                "Abies", (Classification)null, subtree, null, null, null, true, null, null, null, null);
1102
        logFreeTextSearchResults(pager, Level.DEBUG, null);
1103
        Assert.assertEquals("Expecting 3 entity", 3, pager.getCount().intValue());
1104
        Set<UUID> uuids = getTaxonUuidSet(pager);
1105
        Assert.assertTrue("The real synonym should be contained", uuids.contains(ABIES_SUBALPINA_UUID));
1106
        Assert.assertTrue("The pro parte synonym should be contained",uuids.contains(ABIES_LASIOCARPA_UUID));
1107
        Assert.assertTrue("The misapplied name should be contained",uuids.contains(DESC_ABIES_KAWAKAMII_SEC_KOMAROV_UUID));
1108
    }
1109

    
1110
    @Test
1111
    @DataSet
1112
    public final void testFindTaxaAndNamesByFullText_PhraseQuery() throws IOException, LuceneParseException, LuceneMultiSearchException {
1113

    
1114
        refreshLuceneIndex();
1115
        TaxonNode subtree = null;
1116

    
1117
        Pager<SearchResult<TaxonBase>> pager = taxonService.findTaxaAndNamesByFullText(
1118
                EnumSet.of(TaxaAndNamesSearchMode.doTaxa, TaxaAndNamesSearchMode.doSynonyms, TaxaAndNamesSearchMode.includeUnpublished),
1119
                "\"Abies alba\"", null, subtree, null, null, null, true, null, null, null, null);
1120
//        logPagerRecords(pager, Level.DEBUG);
1121
        Assert.assertEquals("doTaxa & doSynonyms with simple phrase query", 1, pager.getCount().intValue());
1122

    
1123
        pager = taxonService.findTaxaAndNamesByFullText(
1124
                EnumSet.of(TaxaAndNamesSearchMode.doTaxa, TaxaAndNamesSearchMode.doSynonyms, TaxaAndNamesSearchMode.includeUnpublished),
1125
                "\"Abies al*\"", null, subtree, null, null, null, true, null, null, null, null);
1126
//        logPagerRecords(pager, Level.DEBUG);
1127
        Assert.assertEquals("doTaxa & doSynonyms with complex phrase query", 1, pager.getCount().intValue());
1128

    
1129
        pager = taxonService.findTaxaAndNamesByFullText(
1130
                EnumSet.of(TaxaAndNamesSearchMode.doTaxa, TaxaAndNamesSearchMode.doSynonyms, TaxaAndNamesSearchMode.includeUnpublished),
1131
                "\"Abies*\"", null, subtree, null, null, null, true, null, null, null, null);
1132
//        logPagerRecords(pager, Level.DEBUG);
1133
        Assert.assertEquals("doTaxa & doSynonyms with simple phrase query", 8, pager.getCount().intValue());
1134

    
1135
        pager = taxonService.findTaxaAndNamesByFullText(
1136
                EnumSet.of(TaxaAndNamesSearchMode.doTaxa, TaxaAndNamesSearchMode.doSynonyms, TaxaAndNamesSearchMode.includeUnpublished),
1137
                "\"Abies*\"", null, subtree, null, null, null, true, null, null, null, null);
1138
//        logPagerRecords(pager, Level.DEBUG);
1139
        Assert.assertEquals("doTaxa & doSynonyms with simple phrase query", 8, pager.getCount().intValue());
1140

    
1141
    }
1142

    
1143
    @Test
1144
    @DataSet
1145
    public final void testFindTaxaAndNamesByFullText_Sort() throws IOException, LuceneParseException, LuceneMultiSearchException {
1146

    
1147
        refreshLuceneIndex();
1148
        TaxonNode subtree = null;
1149

    
1150
        List<OrderHint> orderHints = new ArrayList<>();
1151

    
1152
//        String[] docFields2log = new String[]{"id"};
1153

    
1154
        // SortById
1155
        orderHints.addAll(OrderHint.ORDER_BY_ID.asList());
1156
        Pager<SearchResult<TaxonBase>> pager = taxonService.findTaxaAndNamesByFullText(
1157
                EnumSet.of(TaxaAndNamesSearchMode.doTaxa),
1158
                "Abies", null, subtree, null, null, null, true, null, null, orderHints, null);
1159
//        logSearchResults(pager, Level.DEBUG, docFields2log);
1160
        int lastId = -1;
1161
        for(SearchResult<TaxonBase> rs : pager.getRecords()){
1162
            if(lastId != -1){
1163
                Assert.assertTrue("results not sorted by id", lastId < rs.getEntity().getId());
1164
            }
1165
            lastId = rs.getEntity().getId();
1166
        }
1167

    
1168
        orderHints.addAll(OrderHint.ORDER_BY_ID.asList());
1169
        pager = taxonService.findTaxaAndNamesByFullText(
1170
                EnumSet.of(TaxaAndNamesSearchMode.doTaxa, TaxaAndNamesSearchMode.doSynonyms),
1171
                "Abies", null, subtree, null, null, null, true, null, null, orderHints, null);
1172
//        logSearchResults(pager, Level.DEBUG, docFields2log);
1173

    
1174
        lastId = -1;
1175
        for(SearchResult<TaxonBase> rs : pager.getRecords()){
1176
            if(lastId != -1){
1177
                Assert.assertTrue("results not sorted by id", lastId < rs.getEntity().getId());
1178
            }
1179
            lastId = rs.getEntity().getId();
1180
        }
1181

    
1182
        // Sortby NOMENCLATURAL_SORT_ORDER TODO make assertions !!!
1183
        orderHints.clear();
1184
        orderHints.addAll(OrderHint.NOMENCLATURAL_SORT_ORDER.asList());
1185
        pager = taxonService.findTaxaAndNamesByFullText(
1186
                EnumSet.of(TaxaAndNamesSearchMode.doTaxa, TaxaAndNamesSearchMode.doSynonyms),
1187
                "Abies", null, subtree, null, null, null, true, null, null, orderHints, null);
1188
        logFreeTextSearchResults(pager, Level.DEBUG, null);
1189

    
1190
    }
1191

    
1192
    @Test
1193
    @DataSet
1194
    @Ignore //ignore until #7487 is fixed
1195
    public final void testFindTaxaAndNamesByFullText_AreaFilter_7487() throws IOException, LuceneParseException, LuceneMultiSearchException {
1196
        refreshLuceneIndex();
1197
        TaxonNode subtree = null;
1198
        Set<NamedArea> a_germany_canada_russia = new HashSet<>();
1199
        a_germany_canada_russia.add(germany);
1200
        a_germany_canada_russia.add(canada);
1201
        a_germany_canada_russia.add(russia);
1202

    
1203
        Set<PresenceAbsenceTerm> present_native = new HashSet<>();
1204
        present_native.add(PresenceAbsenceTerm.PRESENT());
1205
        present_native.add(PresenceAbsenceTerm.NATIVE());
1206

    
1207
        Pager<SearchResult<TaxonBase>> pager = taxonService.findTaxaAndNamesByFullText(
1208
                EnumSet.of(TaxaAndNamesSearchMode.doSynonyms, TaxaAndNamesSearchMode.includeUnpublished),
1209
                "Abies", null, subtree, a_germany_canada_russia, present_native, null, true, null, null, null, null);
1210
        Assert.assertEquals("Synonyms with matching area filter", 2, pager.getCount().intValue());
1211
        Set<UUID> uuids = this.getTaxonUuidSet(pager);
1212
        Assert.assertTrue("Synonym of balsamea should be in", uuids.contains(ABIES_SUBALPINA_UUID));
1213
        Assert.assertTrue("Pro parte synonym of balsamea should be in", uuids.contains(ABIES_LASIOCARPA_UUID));
1214

    
1215
        //pro parte syn => partial syn
1216
        Taxon t_abies_balsamea = (Taxon)taxonService.find(ABIES_BALSAMEA_UUID);
1217
        Set<TaxonRelationship> relsTo = t_abies_balsamea.getProParteAndPartialSynonymRelations();
1218
        Assert.assertEquals(1, relsTo.size());
1219
        TaxonRelationship taxonRelation = relsTo.iterator().next();
1220
        taxonRelation.setType(TaxonRelationshipType.PARTIAL_SYNONYM_FOR());
1221
        taxonService.saveOrUpdate(t_abies_balsamea);
1222
        commitAndStartNewTransaction(null);
1223

    
1224
        //should give same results as above
1225
        pager = taxonService.findTaxaAndNamesByFullText(
1226
                EnumSet.of(TaxaAndNamesSearchMode.doSynonyms, TaxaAndNamesSearchMode.includeUnpublished),
1227
                "Abies", null, subtree, a_germany_canada_russia, present_native, null, true, null, null, null, null);
1228
//        Assert.assertEquals("Synonyms with matching area filter", 2, pager.getCount().intValue());
1229
//        uuids = this.getTaxonUuidSet(pager);
1230
//        Assert.assertTrue("Synonym of balsamea should be in", uuids.contains(ABIES_SUBALPINA_UUID));
1231
//        Assert.assertTrue("Partial synonym of balsamea should be in", uuids.contains(ABIES_LASIOCARPA_UUID));
1232

    
1233
        ///MISAPPLIED
1234
        pager = taxonService.findTaxaAndNamesByFullText(
1235
                EnumSet.of(TaxaAndNamesSearchMode.doMisappliedNames, TaxaAndNamesSearchMode.doTaxa, TaxaAndNamesSearchMode.includeUnpublished),
1236
                "Abies", null, subtree, a_germany_canada_russia, present_native, null, true, null, null, null, null);
1237
        Assert.assertEquals("misappliedNames with matching area & status filter", 3, pager.getCount().intValue());
1238
        uuids = this.getTaxonUuidSet(pager);
1239
        Assert.assertTrue("Misapplied name should be in", uuids.contains(DESC_ABIES_KAWAKAMII_SEC_KOMAROV_UUID));
1240

    
1241
        t_abies_balsamea = (Taxon)taxonService.find(ABIES_BALSAMEA_UUID);
1242
        relsTo = t_abies_balsamea.getMisappliedNameRelations();
1243
        Assert.assertEquals(1, relsTo.size());
1244
        taxonRelation = relsTo.iterator().next();
1245
        Assert.assertEquals(taxonRelation.getFromTaxon().getUuid(), DESC_ABIES_KAWAKAMII_SEC_KOMAROV_UUID);
1246
        taxonRelation.setType(TaxonRelationshipType.PRO_PARTE_MISAPPLIED_NAME_FOR());
1247
        taxonService.saveOrUpdate(t_abies_balsamea);
1248
        commitAndStartNewTransaction(null);
1249

    
1250
        //strange it works here before fixing #7487 already
1251
        pager = taxonService.findTaxaAndNamesByFullText(
1252
                EnumSet.of(TaxaAndNamesSearchMode.doMisappliedNames, TaxaAndNamesSearchMode.doTaxa, TaxaAndNamesSearchMode.includeUnpublished),
1253
                "Abies", null, subtree, a_germany_canada_russia, present_native, null, true, null, null, null, null);
1254
        Assert.assertEquals("misappliedNames with matching area & status filter", 3, pager.getCount().intValue());
1255
        uuids = this.getTaxonUuidSet(pager);
1256
        Assert.assertTrue("Pro parte misapplied name should be in", uuids.contains(DESC_ABIES_KAWAKAMII_SEC_KOMAROV_UUID));
1257

    
1258
    }
1259

    
1260

    
1261
    @Test
1262
    @DataSet
1263
    public final void testFindTaxaAndNamesByFullText_AreaFilter() throws IOException, LuceneParseException, LuceneMultiSearchException {
1264

    
1265
        refreshLuceneIndex();
1266
        TaxonNode subtree = null;
1267

    
1268
        Set<NamedArea> a_germany_canada_russia = new HashSet<>();
1269
        a_germany_canada_russia.add(germany);
1270
        a_germany_canada_russia.add(canada);
1271
        a_germany_canada_russia.add(russia);
1272

    
1273
        Set<NamedArea> a_russia = new HashSet<>();
1274
        a_russia.add(russia);
1275

    
1276
        Set<PresenceAbsenceTerm> present = new HashSet<>();
1277
        present.add(PresenceAbsenceTerm.PRESENT());
1278

    
1279
        Set<PresenceAbsenceTerm> present_native = new HashSet<>();
1280
        present_native.add(PresenceAbsenceTerm.PRESENT());
1281
        present_native.add(PresenceAbsenceTerm.NATIVE());
1282

    
1283
        Set<PresenceAbsenceTerm> absent = new HashSet<>();
1284
        absent.add(PresenceAbsenceTerm.ABSENT());
1285

    
1286
        Pager<SearchResult<TaxonBase>> pager = taxonService.findTaxaAndNamesByFullText(
1287
                EnumSet.of(TaxaAndNamesSearchMode.doTaxa, TaxaAndNamesSearchMode.includeUnpublished),
1288
                "Abies", null, subtree, a_germany_canada_russia, null, null, true, null, null, null, null);
1289
        logFreeTextSearchResults(pager, Level.DEBUG, null);
1290
        Assert.assertEquals("Synonyms with matching area filter", 2, pager.getCount().intValue());
1291
        Set<UUID> uuids = this.getTaxonUuidSet(pager);
1292
        Assert.assertTrue("Abies alba (accepted with distribution) should be in", uuids.contains(ABIES_ALBA_UUID));
1293
        Assert.assertTrue("Abies balsamea (accepted with distribution) should be in", uuids.contains(ABIES_BALSAMEA_UUID));
1294

    
1295
        pager = taxonService.findTaxaAndNamesByFullText(
1296
                EnumSet.of(TaxaAndNamesSearchMode.doSynonyms, TaxaAndNamesSearchMode.includeUnpublished),
1297
                "Abies", null, subtree, a_germany_canada_russia, present_native, null, true, null, null, null, null);
1298
        Assert.assertEquals("Synonyms with matching area filter", 2, pager.getCount().intValue());
1299
        uuids = this.getTaxonUuidSet(pager);
1300
        Assert.assertTrue("Synonym of balsamea should be in", uuids.contains(ABIES_SUBALPINA_UUID));
1301
        Assert.assertTrue("Pro parte synonym of balsamea should be in", uuids.contains(ABIES_LASIOCARPA_UUID));
1302

    
1303
        pager = taxonService.findTaxaAndNamesByFullText(
1304
                EnumSet.of(TaxaAndNamesSearchMode.doTaxa, TaxaAndNamesSearchMode.doSynonyms, TaxaAndNamesSearchMode.includeUnpublished),
1305
                "Abies", null, subtree, a_germany_canada_russia, null, null, true, null, null, null, null);
1306
        logFreeTextSearchResults(pager, Level.DEBUG, null);
1307
        Assert.assertEquals("taxa and synonyms with matching area filter", 4, pager.getCount().intValue());
1308
        uuids = this.getTaxonUuidSet(pager);
1309
        Assert.assertTrue("Accepted taxon with area should be in", uuids.contains(ABIES_ALBA_UUID));
1310
        Assert.assertTrue("Accepted taxon with area should be in", uuids.contains(ABIES_BALSAMEA_UUID));
1311
        Assert.assertTrue("Synonym of balsamea should be in", uuids.contains(ABIES_SUBALPINA_UUID));
1312
        Assert.assertTrue("Pro parte synonym of balsamea should be in", uuids.contains(ABIES_LASIOCARPA_UUID));
1313
        Assert.assertFalse("Misapplied name should NOT be in", uuids.contains(DESC_ABIES_KAWAKAMII_SEC_KOMAROV_UUID));
1314

    
1315
        pager = taxonService.findTaxaAndNamesByFullText(
1316
                EnumSet.of(TaxaAndNamesSearchMode.doTaxa, TaxaAndNamesSearchMode.doSynonyms, TaxaAndNamesSearchMode.includeUnpublished),
1317
                "Abies", null, subtree, a_germany_canada_russia, present_native, null, true, null, null, null, null);
1318
        Assert.assertEquals("taxa and synonyms with matching area & status filter 4", 4, pager.getCount().intValue());
1319
        uuids = this.getTaxonUuidSet(pager);
1320
        Assert.assertTrue("Synonym of balsamea should be in", uuids.contains(ABIES_SUBALPINA_UUID));
1321
        Assert.assertTrue("Accepted taxon with area should be in", uuids.contains(ABIES_ALBA_UUID));
1322
        Assert.assertTrue("Synonym of balsamea should be in", uuids.contains(ABIES_SUBALPINA_UUID));
1323
        Assert.assertTrue("Pro parte synonym of balsamea should be in", uuids.contains(ABIES_LASIOCARPA_UUID));
1324

    
1325
        pager = taxonService.findTaxaAndNamesByFullText(
1326
                EnumSet.of(TaxaAndNamesSearchMode.doTaxa, TaxaAndNamesSearchMode.doSynonyms, TaxaAndNamesSearchMode.includeUnpublished),
1327
                "Abies", null, subtree, a_germany_canada_russia, present, null, true, null, null, null, null);
1328
        Assert.assertEquals("taxa and synonyms with matching area & status filter 3", 3, pager.getCount().intValue());
1329
        uuids = this.getTaxonUuidSet(pager);
1330
        Assert.assertTrue("Abies balsamea (accepted taxon) should be in", uuids.contains(ABIES_BALSAMEA_UUID));
1331
        Assert.assertTrue("Synonym of balsamea should be in", uuids.contains(ABIES_SUBALPINA_UUID));
1332
        Assert.assertTrue("Pro parte synonym of balsamea should be in", uuids.contains(ABIES_LASIOCARPA_UUID));
1333

    
1334
        pager = taxonService.findTaxaAndNamesByFullText(
1335
                EnumSet.of(TaxaAndNamesSearchMode.doTaxa, TaxaAndNamesSearchMode.doSynonyms, TaxaAndNamesSearchMode.includeUnpublished),
1336
                "Abies", null, subtree, a_russia, present, null, true, null, null, null, null);
1337
        Assert.assertEquals("taxa and synonyms with non matching area & status filter", 0, pager.getCount().intValue());
1338

    
1339
        pager = taxonService.findTaxaAndNamesByFullText(
1340
                EnumSet.of(TaxaAndNamesSearchMode.doTaxaByCommonNames, TaxaAndNamesSearchMode.includeUnpublished),
1341
                "Tanne", null, subtree, a_germany_canada_russia, present_native, null, true, null, null, null, null);
1342
        Assert.assertEquals("ByCommonNames with area filter", 1, pager.getCount().intValue());
1343
        uuids = this.getTaxonUuidSet(pager);
1344
        Assert.assertTrue("Abies balsamea should be in", uuids.contains(ABIES_BALSAMEA_UUID));
1345

    
1346
        // abies_kawakamii_sensu_komarov as misapplied name for t_abies_balsamea
1347
        pager = taxonService.findTaxaAndNamesByFullText(
1348
                EnumSet.of(TaxaAndNamesSearchMode.doMisappliedNames, TaxaAndNamesSearchMode.includeUnpublished),
1349
                "Abies", null, subtree, a_germany_canada_russia, present_native, null, true, null, null, null, null);
1350
        Assert.assertEquals("misappliedNames with matching area & status filter", 1, pager.getCount().intValue());
1351
        uuids = this.getTaxonUuidSet(pager);
1352
        Assert.assertTrue("Misapplied name should  be in", uuids.contains(DESC_ABIES_KAWAKAMII_SEC_KOMAROV_UUID));
1353

    
1354

    
1355
        // 1. remove existing taxon relation
1356
        Taxon t_abies_balsamea = (Taxon)taxonService.find(ABIES_BALSAMEA_UUID);
1357
        Set<TaxonRelationship> relsTo = t_abies_balsamea.getMisappliedNameRelations();
1358
        Assert.assertEquals(1, relsTo.size());
1359
        TaxonRelationship taxonRelation = relsTo.iterator().next();
1360
        t_abies_balsamea.removeTaxonRelation(taxonRelation);
1361
        taxonService.saveOrUpdate(t_abies_balsamea);
1362
        commitAndStartNewTransaction(null);
1363

    
1364
        pager = taxonService.findTaxaAndNamesByFullText(
1365
                EnumSet.of(TaxaAndNamesSearchMode.doMisappliedNames, TaxaAndNamesSearchMode.includeUnpublished),
1366
                "Abies", null, subtree, a_germany_canada_russia, present_native, null, true, null, null, null, null);
1367
        Assert.assertEquals("misappliedNames with matching area & status filter, should match nothing now", 0, pager.getCount().intValue());
1368

    
1369
        // 2. now add abies_kawakamii_sensu_komarov as misapplied name for t_abies_alba and search for misapplications in Russia: ABSENT
1370
        Taxon t_abies_kawakamii_sensu_komarov = (Taxon)taxonService.find(DESC_ABIES_KAWAKAMII_SEC_KOMAROV_UUID);
1371
        Taxon t_abies_alba = (Taxon)taxonService.find(ABIES_ALBA_UUID);
1372
        t_abies_alba.addMisappliedName(t_abies_kawakamii_sensu_komarov, null, null);
1373
        taxonService.update(t_abies_kawakamii_sensu_komarov);
1374
        commitAndStartNewTransaction(null);
1375

    
1376
        pager = taxonService.findTaxaAndNamesByFullText(
1377
                EnumSet.of(TaxaAndNamesSearchMode.doMisappliedNames, TaxaAndNamesSearchMode.includeUnpublished),
1378
                "Abies", null, subtree, a_germany_canada_russia, absent, null, true, null, null, null, null);
1379
        Assert.assertEquals("misappliedNames with matching area & status filter, should find one", 1, pager.getCount().intValue());
1380
        uuids = this.getTaxonUuidSet(pager);
1381
        Assert.assertTrue("Misapplied name should  be in", uuids.contains(DESC_ABIES_KAWAKAMII_SEC_KOMAROV_UUID));
1382

    
1383
    }
1384

    
1385
    @Test
1386
    @DataSet
1387
    //https://dev.e-taxonomy.eu/redmine/issues/5477
1388
    public final void testFindTaxaAndNamesByFullText_AreaFilter_issue5477() throws IOException, LuceneParseException, LuceneMultiSearchException {
1389

    
1390
        TaxonNode subtree = null;
1391
        Set<NamedArea> a_germany_canada_russia = new HashSet<>();
1392
        a_germany_canada_russia.add(germany);
1393
        a_germany_canada_russia.add(canada);
1394
        a_germany_canada_russia.add(russia);
1395

    
1396

    
1397
        Set<PresenceAbsenceTerm> absent = new HashSet<>();
1398
        absent.add(PresenceAbsenceTerm.ABSENT());
1399

    
1400
        Taxon t_abies_kawakamii_sensu_komarov = (Taxon)taxonService.find(DESC_ABIES_KAWAKAMII_SEC_KOMAROV_UUID);
1401
        Taxon t_abies_alba = (Taxon)taxonService.find(ABIES_ALBA_UUID);
1402
        t_abies_alba.addMisappliedName(t_abies_kawakamii_sensu_komarov, null, null);
1403

    
1404
        /* Since the upgrade from hibernate search 4 to 5.5
1405
         * triggering an update of t_abies_alba is no longer sufficient to also update the
1406
         * document of t_abies_kawakamii_sensu_komarov in the lucene index.
1407
         * the last test in testFindTaxaAndNamesByFullText_AreaFilter() failed in this case.
1408
         * This situation is reproduced here:
1409
         */
1410
        taxonService.update(t_abies_alba);
1411

    
1412
        commitAndStartNewTransaction(null);
1413

    
1414
        Pager<SearchResult<TaxonBase>> pager = taxonService.findTaxaAndNamesByFullText(
1415
                  EnumSet.of(TaxaAndNamesSearchMode.doMisappliedNames),
1416
                  "Abies", null, subtree, a_germany_canada_russia, absent, null, true, null, null, null, null);
1417
        Assert.assertEquals("misappliedNames with matching area & status filter, should find one", 1, pager.getCount().intValue());
1418
    }
1419

    
1420

    
1421
    /**
1422
     * Regression test for #3119: fulltext search: Entity always null whatever search
1423
     *
1424
     * @throws IOException
1425
     * @throws LuceneParseException
1426
     * @throws LuceneMultiSearchException
1427
     */
1428
    @Test
1429
    @DataSet
1430
    public final void testFindByEverythingFullText() throws IOException, LuceneParseException, LuceneMultiSearchException {
1431

    
1432
        refreshLuceneIndex();
1433
        TaxonNode subtree = null;
1434
        EnumSet<TaxaAndNamesSearchMode> mode = TaxaAndNamesSearchMode.taxaAndSynonymsWithUnpublished();
1435
        // via Taxon
1436
        Pager<SearchResult<TaxonBase>>pager = taxonService.findByEverythingFullText("Abies", null, subtree, includeUnpublished, null, true, null, null, null, null);
1437
//        Pager<SearchResult<TaxonBase>> pager = taxonService.findTaxaAndNamesByFullText(mode,
1438
//                "Abies", null, null, null, null, true, null, null, null, null);
1439
        logFreeTextSearchResults(pager, Level.DEBUG, null);
1440
        Assert.assertTrue("Expecting at least 7 entities for 'Abies'", pager.getCount() > 7);
1441
        Assert.assertNotNull("Expecting entity", pager.getRecords().get(0).getEntity());
1442
//        Assert.assertEquals("Expecting Taxon entity", Taxon.class, pager.getRecords().get(0).getEntity().getClass());
1443

    
1444
        // via DescriptionElement
1445
        pager = taxonService.findByEverythingFullText("present", null, subtree, includeUnpublished, null, true, null, null, null, null);
1446
        //this is not covered by findTaxaAndNamesByFullText
1447
//        pager = taxonService.findTaxaAndNamesByFullText(mode,
1448
//                "present", null, null, null, null, true, null, null, null, null);
1449
        Assert.assertEquals("Expecting one entity when searching for area 'present'", 1, pager.getCount().intValue());
1450
        Assert.assertNotNull("Expecting entity", pager.getRecords().get(0).getEntity());
1451
        Assert.assertEquals("Expecting Taxon entity", Taxon.class, CdmBase.deproxy(pager.getRecords().get(0).getEntity()).getClass());
1452
        Assert.assertEquals("Expecting Taxon ", ABIES_BALSAMEA_UUID, pager.getRecords().get(0).getEntity().getUuid());
1453

    
1454
    }
1455

    
1456

    
1457
    @Test
1458
    @DataSet
1459
    public final void findByEveryThingFullText() throws IOException, LuceneParseException, LuceneMultiSearchException {
1460

    
1461
        refreshLuceneIndex();
1462
        TaxonNode subtree = null;
1463

    
1464
        Classification classification = null;
1465
        EnumSet<TaxaAndNamesSearchMode> mode = TaxaAndNamesSearchMode.taxaAndSynonymsWithUnpublished();
1466

    
1467
        Pager<SearchResult<TaxonBase>> pager = taxonService.findByEverythingFullText("genus", null, subtree, includeUnpublished, null, false, null, null, null, null); // --> 1
1468
//        Pager<SearchResult<TaxonBase>> pager = taxonService.findTaxaAndNamesByFullText(mode,
1469
//                "genus", classification, null, null, null, false, null, null, null, null);
1470
        Assert.assertEquals("Expecting 1 entity", 1, pager.getCount().intValue());
1471

    
1472
        //FIXME FAILS: abies balamea is returned twice, see also testFullText_Grouping()
1473
        pager = taxonService.findByEverythingFullText("Balsam", null, subtree, includeUnpublished, Arrays.asList(new Language[]{Language.GERMAN()}), false, null, null, null, null);
1474
        logFreeTextSearchResults(pager, Level.DEBUG, null);
1475
//        pager = taxonService.findTaxaAndNamesByFullText(EnumSet.allOf(TaxaAndNamesSearchMode.class),
1476
//                "Balsam", classification, null, null, Arrays.asList(new Language[]{Language.GERMAN()}), false, null, null, null, null);
1477
        Assert.assertEquals("expecting to find the Abies balsamea via the GERMAN DescriptionElements", 1, pager.getCount().intValue());
1478

    
1479
        //TODO fieldHighlight does not yet work
1480
        pager = taxonService.findByEverythingFullText("Abies", null, subtree, includeUnpublished, null, true, null, null, null, null);
1481
//        pager = taxonService.findTaxaAndNamesByFullText(mode,
1482
//                "Abies", classification, null, null, Arrays.asList(new Language[]{Language.GERMAN()}), false, null, null, null, null);
1483
        Assert.assertEquals("Expecting 8 entities", 8, pager.getCount().intValue());
1484
        SearchResult<TaxonBase> searchResult = pager.getRecords().get(0);
1485
        Assert.assertTrue("the map of highlighted fragments should contain at least one item", searchResult.getFieldHighlightMap().size() > 0);
1486
        String[] fragments = searchResult.getFieldHighlightMap().values().iterator().next();
1487
        Assert.assertTrue("first fragments should contains serch term", fragments[0].toLowerCase().contains("<b>abies</b>"));
1488
    }
1489

    
1490
//    @SuppressWarnings("rawtypes")
1491
//    @Test
1492
//    @DataSet
1493
//    public final void benchmarkFindTaxaAndNamesHql() throws IOException, LuceneParseException {
1494
//
1495
//        createRandomTaxonWithCommonName(NUM_OF_NEW_RADOM_ENTITIES);
1496
//
1497
//        IFindTaxaAndNamesConfigurator configurator = new FindTaxaAndNamesConfiguratorImpl();
1498
//        configurator.setTitleSearchString("Wei"+UTF8.SHARP_S+"%");
1499
//        configurator.setMatchMode(MatchMode.BEGINNING);
1500
//        configurator.setDoTaxa(false);
1501
//        configurator.setDoSynonyms(false);
1502
//        configurator.setDoNamesWithoutTaxa(false);
1503
//        configurator.setDoTaxaByCommonNames(true);
1504
//
1505
//        Pager<IdentifiableEntity> pager;
1506
//
1507
//        long startMillis = System.currentTimeMillis();
1508
//        for (int indx = 0; indx < BENCHMARK_ROUNDS; indx++) {
1509
//            pager = taxonService.findTaxaAndNames(configurator);
1510
//            if (logger.isDebugEnabled()) {
1511
//                logger.debug("[" + indx + "]" + pager.getRecords().get(0).getTitleCache());
1512
//            }
1513
//        }
1514
//        double duration = ((double) (System.currentTimeMillis() - startMillis)) / BENCHMARK_ROUNDS;
1515
//        logger.info("Benchmark result - [find taxon by CommonName via HQL] : " + duration + "ms (" + BENCHMARK_ROUNDS + " benchmark rounds )");
1516
//    }
1517

    
1518
    @SuppressWarnings("rawtypes")
1519
    @Test
1520
    @DataSet
1521
    public final void benchmarkFindByCommonNameHql() {
1522

    
1523
//        printDataSet(System.err, new String[] { "TaxonBase" });
1524

    
1525
        createRandomTaxonWithCommonName(NUM_OF_NEW_RADOM_ENTITIES);
1526

    
1527
        IFindTaxaAndNamesConfigurator configurator = FindTaxaAndNamesConfiguratorImpl.NewInstance();
1528
        configurator.setTitleSearchString("Wei"+UTF8.SHARP_S+"%");
1529
        configurator.setMatchMode(MatchMode.BEGINNING);
1530
        configurator.setDoTaxa(false);
1531
        configurator.setDoSynonyms(false);
1532
        configurator.setDoNamesWithoutTaxa(false);
1533
        configurator.setDoTaxaByCommonNames(true);
1534

    
1535
        Pager<IdentifiableEntity> pager;
1536

    
1537
        long startMillis = System.currentTimeMillis();
1538
        for (int indx = 0; indx < BENCHMARK_ROUNDS; indx++) {
1539
            pager = taxonService.findTaxaAndNames(configurator);
1540
            if (logger.isDebugEnabled()) {
1541
                logger.debug("[" + indx + "]" + pager.getRecords().get(0).getTitleCache());
1542
            }
1543
        }
1544
        double duration = ((double) (System.currentTimeMillis() - startMillis)) / BENCHMARK_ROUNDS;
1545
        logger.info("Benchmark result - [find taxon by CommonName via HQL] : " + duration + "ms (" + BENCHMARK_ROUNDS + " benchmark rounds )");
1546
    }
1547

    
1548
    @SuppressWarnings("rawtypes")
1549
    @Test
1550
    @DataSet
1551
    public final void benchmarkFindByCommonNameLucene() throws IOException, LuceneParseException {
1552
        TaxonNode subtree = null;
1553
        createRandomTaxonWithCommonName(NUM_OF_NEW_RADOM_ENTITIES);
1554

    
1555
        refreshLuceneIndex();
1556

    
1557
        Pager<SearchResult<TaxonBase>> pager;
1558

    
1559
        long startMillis = System.currentTimeMillis();
1560
        for (int indx = 0; indx < BENCHMARK_ROUNDS; indx++) {
1561
            pager = taxonService.findByDescriptionElementFullText(CommonTaxonName.class, "Wei"+UTF8.SHARP_S+"*", null, subtree, null, null, false, null, null, null, null);
1562
            if (logger.isDebugEnabled()) {
1563
                logger.debug("[" + indx + "]" + pager.getRecords().get(0).getEntity().getTitleCache());
1564
            }
1565
        }
1566
        double duration = ((double) (System.currentTimeMillis() - startMillis)) / BENCHMARK_ROUNDS;
1567
        logger.info("Benchmark result - [find taxon by CommonName via lucene] : " + duration + "ms (" + BENCHMARK_ROUNDS + " benchmark rounds )");
1568
    }
1569

    
1570
    /**
1571
     * uncomment @Test annotation to create the dataset for this test
1572
     */
1573
    @Override
1574
    //    @Test
1575
    @DataSet(loadStrategy=CleanSweepInsertLoadStrategy.class, value="ClearDBDataSet.xml")
1576
    public final void createTestDataSet() throws FileNotFoundException {
1577

    
1578
        Classification europeanAbiesClassification = Classification.NewInstance("European Abies");
1579
        europeanAbiesClassification.setUuid(CLASSIFICATION_UUID);
1580
        classificationService.save(europeanAbiesClassification);
1581

    
1582
        Classification alternativeClassification = Classification.NewInstance("Abies alternative");
1583
        alternativeClassification.setUuid(CLASSIFICATION_ALT_UUID);
1584
        classificationService.save(alternativeClassification);
1585

    
1586
        Reference sec = ReferenceFactory.newBook();
1587
        sec.setTitleCache("Kohlbecker, A., Testcase standart views, 2013", true);
1588
        Reference sec_sensu = ReferenceFactory.newBook();
1589
        sec_sensu.setTitleCache("Komarov, V. L., Flora SSSR 29", true);
1590
        referenceService.save(sec);
1591
        referenceService.save(sec_sensu);
1592

    
1593
        IBotanicalName n_abies = TaxonNameFactory.NewBotanicalInstance(Rank.GENUS());
1594
        n_abies.setNameCache("Abies", true);
1595
        Taxon t_abies = Taxon.NewInstance(n_abies, sec);
1596
        taxonService.save(t_abies);
1597

    
1598
        IBotanicalName n_abies_alba = TaxonNameFactory.NewBotanicalInstance(Rank.SPECIES());
1599
        n_abies_alba.setNameCache("Abies alba", true);
1600
        Taxon t_abies_alba = Taxon.NewInstance(n_abies_alba, sec);
1601
        t_abies_alba.setUuid(ABIES_ALBA_UUID);
1602
        taxonService.save(t_abies_alba);
1603

    
1604
        IBotanicalName n_abies_subalpina = TaxonNameFactory.NewBotanicalInstance(Rank.SPECIES());
1605
        n_abies_subalpina.setNameCache("Abies subalpina", true);
1606
        Synonym s_abies_subalpina = Synonym.NewInstance(n_abies_subalpina, sec);
1607
        taxonService.save(s_abies_subalpina);
1608

    
1609
        IBotanicalName n_abies_balsamea = TaxonNameFactory.NewBotanicalInstance(Rank.SPECIES());
1610
        n_abies_balsamea.setNameCache("Abies balsamea", true);
1611
        Taxon t_abies_balsamea = Taxon.NewInstance(n_abies_balsamea, sec);
1612
        t_abies_balsamea.setUuid(ABIES_BALSAMEA_UUID);
1613
        t_abies_balsamea.addSynonym(s_abies_subalpina, SynonymType.SYNONYM_OF());
1614
        taxonService.save(t_abies_balsamea);
1615

    
1616
        IBotanicalName n_abies_grandis = TaxonNameFactory.NewBotanicalInstance(Rank.SPECIES());
1617
        n_abies_grandis.setNameCache("Abies grandis", true);
1618
        Taxon t_abies_grandis = Taxon.NewInstance(n_abies_grandis, sec);
1619
        taxonService.save(t_abies_grandis);
1620

    
1621
        IBotanicalName n_abies_kawakamii = TaxonNameFactory.NewBotanicalInstance(Rank.SPECIES());
1622
        n_abies_kawakamii.setNameCache("Abies kawakamii", true);
1623
        Taxon t_abies_kawakamii = Taxon.NewInstance(n_abies_kawakamii, sec);
1624
        t_abies_kawakamii.getTitleCache();
1625
        taxonService.save(t_abies_kawakamii);
1626

    
1627
        // abies_kawakamii_sensu_komarov as missapplied name for t_abies_balsamea
1628
        Taxon t_abies_kawakamii_sensu_komarov = Taxon.NewInstance(n_abies_kawakamii, sec_sensu);
1629
        taxonService.save(t_abies_kawakamii_sensu_komarov);
1630
        t_abies_kawakamii_sensu_komarov.addTaxonRelation(t_abies_balsamea, TaxonRelationshipType.MISAPPLIED_NAME_FOR(), null, null);
1631
        taxonService.saveOrUpdate(t_abies_kawakamii_sensu_komarov);
1632

    
1633
        IBotanicalName n_abies_lasiocarpa = TaxonNameFactory.NewBotanicalInstance(Rank.SPECIES());
1634
        n_abies_lasiocarpa.setNameCache("Abies lasiocarpa", true);
1635
        Taxon t_abies_lasiocarpa = Taxon.NewInstance(n_abies_lasiocarpa, sec);
1636
        taxonService.save(t_abies_lasiocarpa);
1637

    
1638
        // add taxa to classifications
1639
        europeanAbiesClassification.addChildTaxon(t_abies_balsamea, null, null);
1640
        alternativeClassification.addChildTaxon(t_abies_lasiocarpa, null, null);
1641
        classificationService.saveOrUpdate(europeanAbiesClassification);
1642
        classificationService.saveOrUpdate(alternativeClassification);
1643

    
1644
        //
1645
        // Description
1646
        //
1647
        TaxonDescription d_abies_alba = TaxonDescription.NewInstance(t_abies_alba);
1648
        TaxonDescription d_abies_balsamea = TaxonDescription.NewInstance(t_abies_balsamea);
1649

    
1650
        d_abies_alba.setUuid(DESC_ABIES_ALBA_UUID);
1651
        d_abies_balsamea.setUuid(DESC_ABIES_BALSAMEA_UUID);
1652

    
1653

    
1654
        // CommonTaxonName
1655
        d_abies_alba.addElement(CommonTaxonName.NewInstance("Wei"+UTF8.SHARP_S+"tanne", Language.GERMAN()));
1656
        d_abies_alba.addElement(CommonTaxonName.NewInstance("silver fir", Language.ENGLISH()));
1657
        d_abies_alba.addElement(Distribution
1658
                .NewInstance(
1659
                        germany,
1660
                        PresenceAbsenceTerm.NATIVE()));
1661
        d_abies_alba.addElement(Distribution
1662
                .NewInstance(
1663
                        russia,
1664
                        PresenceAbsenceTerm.ABSENT()));
1665

    
1666
        // TextData
1667
        d_abies_balsamea
1668
            .addElement(TextData
1669
                    .NewInstance(
1670
                            "Die Balsam-Tanne (Abies balsamea) ist eine Pflanzenart aus der Gattung der Tannen (Abies). Sie wächst im nordöstlichen Nordamerika, wo sie sowohl Tief- als auch Bergland besiedelt. Sie gilt als relativ anspruchslos gegenüber dem Standort und ist frosthart. In vielen Teilen des natürlichen Verbreitungsgebietes stellt sie die Klimaxbaumart dar.",
1671
                            Language.GERMAN(), null));
1672
        d_abies_balsamea
1673
        .addElement(CommonTaxonName
1674
                .NewInstance(
1675
                        "Balsam-Tanne",
1676
                        Language.GERMAN(), null));
1677

    
1678
        d_abies_balsamea
1679
        .addElement(Distribution
1680
                .NewInstance(
1681
                        canada,
1682
                        PresenceAbsenceTerm.PRESENT()));
1683

    
1684
        d_abies_balsamea
1685
        .addElement(Distribution
1686
                .NewInstance(
1687
                        germany,
1688
                        PresenceAbsenceTerm.NATIVE()));
1689

    
1690
        d_abies_balsamea
1691
                .addElement(TextData
1692
                        .NewInstance(
1693
                                TaxonServiceSearchTestUtf8Constants.RUSSIAN_ABIES_ALBA_LONG,
1694
                                Language.RUSSIAN(), null));
1695
        d_abies_balsamea
1696
        .addElement(CommonTaxonName
1697
                .NewInstance(
1698
                        TaxonServiceSearchTestUtf8Constants.RUSSIAN_ABIES_ALBA_SHORT,
1699
                        Language.RUSSIAN(), null));
1700
        descriptionService.saveOrUpdate(d_abies_balsamea);
1701

    
1702
        setComplete();
1703
        endTransaction();
1704

    
1705

    
1706
        writeDbUnitDataSetFile(new String[] {
1707
            "TAXONBASE", "TAXONNAME",
1708
            "TAXONRELATIONSHIP",
1709
            "REFERENCE", "DESCRIPTIONELEMENTBASE", "DESCRIPTIONBASE",
1710
            "AGENTBASE", "HOMOTYPICALGROUP",
1711
            "CLASSIFICATION", "TAXONNODE",
1712
            "LANGUAGESTRING", "DESCRIPTIONELEMENTBASE_LANGUAGESTRING",
1713
            "HIBERNATE_SEQUENCES" // IMPORTANT!!!
1714
            });
1715

    
1716
    }
1717

    
1718
    /**
1719
     *
1720
     */
1721
    private void refreshLuceneIndex() {
1722

    
1723
//        commitAndStartNewTransaction(null);
1724
        commit();
1725
        endTransaction();
1726
        indexer.purge(DefaultProgressMonitor.NewInstance());
1727
        indexer.reindex(typesToIndex, DefaultProgressMonitor.NewInstance());
1728
        startNewTransaction();
1729
//        commitAndStartNewTransaction(null);
1730
    }
1731

    
1732
    /**
1733
     * @param numberOfNew
1734
     *
1735
     */
1736
    private void createRandomTaxonWithCommonName(int numberOfNew) {
1737

    
1738
        logger.debug(String.format("creating %1$s random taxan with CommonName", numberOfNew));
1739

    
1740
        commitAndStartNewTransaction(null);
1741

    
1742
        Reference sec = ReferenceFactory.newBook();
1743
        referenceService.save(sec);
1744

    
1745
        for (int i = numberOfNew; i < numberOfNew; i++) {
1746
            RandomStringUtils.randomAlphabetic(10);
1747
            String radomName = RandomStringUtils.randomAlphabetic(5) + " " + RandomStringUtils.randomAlphabetic(10);
1748
            String radomCommonName = RandomStringUtils.randomAlphabetic(10);
1749

    
1750
            IBotanicalName name = TaxonNameFactory.NewBotanicalInstance(Rank.SPECIES());
1751
            name.setNameCache(radomName, true);
1752
            Taxon taxon = Taxon.NewInstance(name, sec);
1753
            taxonService.save(taxon);
1754

    
1755
            TaxonDescription description = TaxonDescription.NewInstance(taxon);
1756
            description.addElement(CommonTaxonName.NewInstance(radomCommonName, Language.GERMAN()));
1757
            descriptionService.save(description);
1758
        }
1759

    
1760
        commitAndStartNewTransaction(null);
1761
    }
1762

    
1763
    private <T extends CdmBase> void logFreeTextSearchResults(Pager<SearchResult<T>> pager, Level level, String[] docFields){
1764
        if(level == null){
1765
            level = Level.DEBUG;
1766
        }
1767
        if(logger.isEnabledFor(level)){
1768
            StringBuilder b = new StringBuilder();
1769
            b.append("\n");
1770
            int i = 0;
1771
            for(SearchResult<?> sr : pager.getRecords()){
1772

    
1773
                b.append(" ").append(i++).append(" - ");
1774
                b.append("score:").append(sr.getScore()).append(", ");
1775

    
1776
                if(docFields != null){
1777
                    b.append("docs : ");
1778
                    for(Document doc : sr.getDocs()) {
1779
                        b.append("<");
1780
                        for(String f : docFields){
1781
                            b.append(f).append(":").append(Arrays.toString(doc.getValues(f)));
1782
                        }
1783
                        b.append(">");
1784
                    }
1785
                }
1786

    
1787
                CdmBase entity = sr.getEntity();
1788
                if(entity == null){
1789
                    b.append("NULL");
1790
                } else {
1791
                    b.append(entity.getClass().getSimpleName()).
1792
                        append(" [").append(entity.getId()).
1793
                        append(" | ").append(entity.getUuid()).append("] : ").
1794
                        append(entity.toString());
1795

    
1796
                }
1797
                b.append("\n");
1798
            }
1799
            logger.log(level, b);
1800
        }
1801
    }
1802

    
1803

    
1804
    /**
1805
     * @param pager
1806
     * @return
1807
     */
1808
    private Set<UUID> getTaxonUuidSet(@SuppressWarnings("rawtypes") Pager<SearchResult<TaxonBase>> pager) {
1809
        Set<UUID> result = new HashSet<>();
1810
        for (@SuppressWarnings("rawtypes") SearchResult<TaxonBase> searchResult : pager.getRecords()){
1811
            result.add(searchResult.getEntity().getUuid());
1812
        }
1813
        return result;
1814
    }
1815

    
1816
}
(32-32/37)