/*
* (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* Delbosc Benoit
*/
package org.nuxeo.elasticsearch.test;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.DocumentModelList;
import org.nuxeo.elasticsearch.api.ElasticSearchAdmin;
import org.nuxeo.elasticsearch.api.ElasticSearchService;
import org.nuxeo.elasticsearch.query.NxQueryBuilder;
import org.nuxeo.runtime.test.runner.Deploy;
import org.nuxeo.runtime.test.runner.Features;
import org.nuxeo.runtime.test.runner.FeaturesRunner;
import org.nuxeo.runtime.test.runner.LocalDeploy;
import org.nuxeo.runtime.transaction.TransactionHelper;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
@RunWith(FeaturesRunner.class)
@Features({ RepositoryElasticSearchFeature.class })
@Deploy({ "org.nuxeo.ecm.platform.tag", "org.nuxeo.ecm.platform.ws", "org.nuxeo.ecm.automation.core" })
@LocalDeploy("org.nuxeo.elasticsearch.core:elasticsearch-test-mapping-contrib.xml")
public class TestMapping {
@Inject
protected CoreSession session;
@Inject
protected ElasticSearchService ess;
@Inject
ElasticSearchAdmin esa;
private int commandProcessed;
public void assertNumberOfCommandProcessed(int processed) throws Exception {
Assert.assertEquals(processed, esa.getTotalCommandProcessed() - commandProcessed);
}
/**
* Wait for sync and async job and refresh the index
*/
public void waitForIndexing() throws Exception {
esa.prepareWaitForIndexing().get(20, TimeUnit.SECONDS);
esa.refresh();
}
public void startTransaction() {
if (!TransactionHelper.isTransactionActive()) {
TransactionHelper.startTransaction();
}
Assert.assertEquals(0, esa.getPendingWorkerCount());
commandProcessed = esa.getTotalCommandProcessed();
}
@Before
public void setUpMapping() throws Exception {
esa.initIndexes(true);
}
@Test
public void testIlikeSearch() throws Exception {
startTransaction();
DocumentModel doc = session.createDocumentModel("/", "testDoc1", "File");
doc.setPropertyValue("dc:title", "upper case");
doc.setPropertyValue("dc:description", "UPPER CASE DESC");
doc = session.createDocument(doc);
doc = session.createDocumentModel("/", "testDoc2", "File");
doc.setPropertyValue("dc:title", "mixed case");
doc.setPropertyValue("dc:description", "MiXeD cAsE dEsC");
doc = session.createDocument(doc);
doc = session.createDocumentModel("/", "testDoc3", "File");
doc.setPropertyValue("dc:title", "lower case");
doc.setPropertyValue("dc:description", "lower case desc");
doc = session.createDocument(doc);
TransactionHelper.commitOrRollbackTransaction();
waitForIndexing();
assertNumberOfCommandProcessed(3);
startTransaction();
DocumentModelList ret = ess.query(new NxQueryBuilder(session).nxql("SELECT * FROM Document WHERE dc:description ILIKE '%Case%'"));
Assert.assertEquals(3, ret.totalSize());
ret = ess.query(new NxQueryBuilder(session).nxql("SELECT * FROM Document WHERE dc:description ILIKE 'Upper%'"));
Assert.assertEquals(1, ret.totalSize());
ret = ess.query(new NxQueryBuilder(session).nxql("SELECT * FROM Document WHERE dc:description ILIKE 'mixED case desc'"));
Assert.assertEquals(1, ret.totalSize());
// case sensitive for other operation
ret = ess.query(new NxQueryBuilder(session).nxql("SELECT * FROM Document WHERE dc:description LIKE '%Case%'"));
Assert.assertEquals(0, ret.totalSize());
ret = ess.query(new NxQueryBuilder(session).nxql("SELECT * FROM Document WHERE dc:description LIKE 'Upper%'"));
Assert.assertEquals(0, ret.totalSize());
ret = ess.query(new NxQueryBuilder(session).nxql("SELECT * FROM Document WHERE dc:description LIKE 'UPPER%'"));
Assert.assertEquals(1, ret.totalSize());
}
@Test
public void testFulltextAnalyzer() throws Exception {
startTransaction();
DocumentModel doc = session.createDocumentModel("/", "testDoc1", "File");
doc.setPropertyValue("dc:title", "new-york.jpg");
doc = session.createDocument(doc);
doc = session.createDocumentModel("/", "testDoc2", "File");
doc.setPropertyValue("dc:title", "York.jpg");
doc = session.createDocument(doc);
doc = session.createDocumentModel("/", "testDoc3", "File");
doc.setPropertyValue("dc:title", "foo_jpg");
doc = session.createDocument(doc);
TransactionHelper.commitOrRollbackTransaction();
waitForIndexing();
startTransaction();
DocumentModelList ret = ess.query(new NxQueryBuilder(session).nxql("SELECT * FROM Document WHERE ecm:fulltext.dc:title = 'new-york.jpg'"));
Assert.assertEquals(1, ret.totalSize());
// The standard tokenizer first split new-york.jpg in "new" "york.jpg"
// then the word delimiter gives: "new" york" "jpg" "york.jpg"
ret = ess.query(new NxQueryBuilder(session).nxql("SELECT * FROM Document WHERE ecm:fulltext.dc:title = 'new york jpg'"));
Assert.assertEquals(1, ret.totalSize());
ret = ess.query(new NxQueryBuilder(session).nxql("SELECT * FROM Document WHERE ecm:fulltext.dc:title = 'new-york'"));
Assert.assertEquals(1, ret.totalSize());
ret = ess.query(new NxQueryBuilder(session).nxql("SELECT * FROM Document WHERE ecm:fulltext.dc:title = 'york new'"));
Assert.assertEquals(1, ret.totalSize());
ret = ess.query(new NxQueryBuilder(session).nxql("SELECT * FROM Document WHERE ecm:fulltext.dc:title = 'york -new-york'"));
Assert.assertEquals(1, ret.totalSize());
Assert.assertEquals("testDoc2", ret.get(0).getName());
ret = ess.query(new NxQueryBuilder(session).nxql("SELECT * FROM Document WHERE ecm:fulltext.dc:title = 'NewYork'"));
Assert.assertEquals(1, ret.totalSize());
ret = ess.query(new NxQueryBuilder(session).nxql("SELECT * FROM Document WHERE ecm:fulltext.dc:title = 'jpg'"));
Assert.assertEquals(3, ret.totalSize());
}
@Test
public void testNgramSearch() throws Exception {
startTransaction();
DocumentModel doc = session.createDocumentModel("/", "testDoc1", "File");
doc.setPropertyValue("dc:title", "FooBar12 test");
doc = session.createDocument(doc);
doc = session.createDocumentModel("/", "testDoc2", "File");
doc.setPropertyValue("dc:title", "foobar42");
doc = session.createDocument(doc);
TransactionHelper.commitOrRollbackTransaction();
waitForIndexing();
startTransaction();
// Common left/right truncature with a ILIKE, translated into wilcard search *oba* with poor performance
DocumentModelList ret = ess.query(new NxQueryBuilder(session).nxql("SELECT * FROM Document WHERE dc:title ILIKE '%Oba%'"));
Assert.assertEquals(2, ret.totalSize());
// Use an ngram index
ret = ess.query(new NxQueryBuilder(session).nxql("SELECT * FROM Document WHERE /*+ES: INDEX(dc:title.ngram) ANALYZER(lowercase_analyzer) OPERATOR(match) */ dc:title = 'ObA'"));
Assert.assertEquals(2, ret.totalSize());
ret = ess.query(new NxQueryBuilder(session).nxql("SELECT * FROM Document WHERE /*+ES: INDEX(dc:title.ngram) ANALYZER(lowercase_analyzer) OPERATOR(match) */ dc:title = 'fOObar42'"));
Assert.assertEquals(1, ret.totalSize());
// No tokenizer mind the space
ret = ess.query(new NxQueryBuilder(session).nxql("SELECT * FROM Document WHERE /*+ES: INDEX(dc:title.ngram) ANALYZER(lowercase_analyzer) OPERATOR(match) */ dc:title = '2 t'"));
Assert.assertEquals(1, ret.totalSize());
// need to provide min_ngram (3) or more characters
ret = ess.query(new NxQueryBuilder(session).nxql("SELECT * FROM Document WHERE /*+ES: INDEX(dc:title.ngram) ANALYZER(lowercase_analyzer) OPERATOR(match) */ dc:title = '42'"));
Assert.assertEquals(0, ret.totalSize());
// If we don't set the proper analyzer the searched term is also ngramized matching too much
ret = ess.query(new NxQueryBuilder(session).nxql("SELECT * FROM Document WHERE /*+ES: INDEX(dc:title.ngram) OPERATOR(match) */ dc:title = 'ZOObar'"));
Assert.assertEquals(2, ret.totalSize());
// Using the lowercase analyzer for the search term and a ngram max_gram greater than the search term make it work
ret = ess.query(new NxQueryBuilder(session).nxql("SELECT * FROM Document WHERE /*+ES: INDEX(dc:title.ngram) ANALYZER(lowercase_analyzer) OPERATOR(match) */ dc:title = 'ZOObar'"));
Assert.assertEquals(0, ret.totalSize());
}
}