/*******************************************************************************
* Copyright (c) 2010-2014 SAP AG and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* SAP AG - initial API and implementation
*******************************************************************************/
package org.eclipse.skalli.core.search;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.eclipse.skalli.services.extension.ExtensionService;
import org.eclipse.skalli.services.search.FacetedSearchResult;
import org.eclipse.skalli.services.search.PagingInfo;
import org.eclipse.skalli.services.search.SearchResult;
import org.eclipse.skalli.testutil.BundleManager;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.osgi.framework.ServiceRegistration;
@SuppressWarnings("nls")
public class LuceneIndexTest {
public static final String FIELD = "value";
public static final String FACET = "facet";
@SuppressWarnings("rawtypes")
private ServiceRegistration<ExtensionService> serviceRegistration;
private TestEntity entity1;
private TestEntity entity2;
private TestEntity entity3;
private TestEntity entity4;
private TestEntity entity5;
private List<TestEntity> entities;
private LuceneIndex<TestEntity> idx;
@Before
public void setup() throws Exception {
serviceRegistration = BundleManager.registerService(ExtensionService.class, new TestExtensionService(), null);
Assert.assertNotNull(serviceRegistration);
entity1 = new TestEntity("bob", "firstname");
entity2 = new TestEntity("alice", "firstname");
entity3 = new TestEntity("alice smith", "fullname");
entity4 = new TestEntity("alice in wonderland", "sentence");
entity5 = new TestEntity("alice is used in many examples", "sentence");
entities = new LinkedList<TestEntity>();
entities.add(entity1);
entities.add(entity2);
entities.add(entity3);
entities.add(entity4);
entities.add(entity5);
idx = new LuceneIndex<TestEntity>(new TestEntityService(entities));
idx.reindexAll();
}
@After
public void tearDown() {
if (serviceRegistration != null) {
serviceRegistration.unregister();
}
}
@Test
public void testSearch() throws Exception {
SearchResult<TestEntity> res = idx.search(new String[] { FIELD }, "bob", null);
Assert.assertNotNull(res);
Assert.assertEquals(1, res.getResultCount());
Assert.assertNotNull(res.getResult());
Assert.assertEquals(1, res.getResult().size());
Assert.assertEquals("bob", res.getResult().get(0).getEntity().getValue());
Assert.assertEquals("bob", res.getResult().get(0).getValue(FIELD, false));
Assert.assertEquals("<em>bob</em>", res.getResult().get(0).getValue(FIELD, true));
}
@Test
public void testSearch_specialChars() throws Exception {
SearchResult<TestEntity> res = idx.search(new String[] { FIELD }, "(", null);
Assert.assertNotNull(res);
Assert.assertEquals(0, res.getResultCount());
Assert.assertNotNull(res.getResult());
Assert.assertEquals(0, res.getResult().size());
}
@Test
public void testSearch_specialChars_asterisk() throws Exception {
SearchResult<TestEntity> res = idx.search(new String[] { FIELD }, "*", null);
Assert.assertNotNull(res);
Assert.assertEquals(entities.size(), res.getResultCount());
Assert.assertNotNull(res.getResult());
Assert.assertEquals(entities.size(), res.getResult().size());
}
@Test
public void testSearch_pagination() throws Exception {
PagingInfo pi1 = new PagingInfo(0, 2);
SearchResult<TestEntity> res1 = idx.search(new String[] { FIELD }, "alice", pi1);
Assert.assertNotNull(res1);
Assert.assertEquals(4, res1.getResultCount());
Assert.assertNotNull(res1.getResult());
Assert.assertEquals(2, res1.getResult().size());
Assert.assertEquals("alice", res1.getResult().get(0).getEntity().getValue());
Assert.assertEquals("alice", res1.getResult().get(0).getValue(FIELD, false));
Assert.assertEquals("<em>alice</em>", res1.getResult().get(0).getValue(FIELD, true));
Assert.assertEquals("alice smith", res1.getResult().get(1).getEntity().getValue());
Assert.assertEquals("alice smith", res1.getResult().get(1).getValue(FIELD, false));
Assert.assertEquals("<em>alice</em> smith", res1.getResult().get(1).getValue(FIELD, true));
PagingInfo pi2 = new PagingInfo(1, 2);
SearchResult<TestEntity> res2 = idx.search(new String[] { FIELD }, "alice", pi2);
Assert.assertNotNull(res2);
Assert.assertEquals(4, res2.getResultCount());
Assert.assertNotNull(res2.getResult());
Assert.assertEquals(2, res2.getResult().size());
Assert.assertEquals("alice smith", res2.getResult().get(0).getEntity().getValue());
Assert.assertEquals("alice smith", res2.getResult().get(0).getValue(FIELD, false));
Assert.assertEquals("<em>alice</em> smith", res2.getResult().get(0).getValue(FIELD, true));
Assert.assertEquals("alice in wonderland", res2.getResult().get(1).getEntity().getValue());
Assert.assertEquals("alice in wonderland", res2.getResult().get(1).getValue(FIELD, false));
Assert.assertEquals("<em>alice</em> in wonderland", res2.getResult().get(1).getValue(FIELD, true));
}
@Test
public void testUpdate() throws Exception {
// first ensure there is no hit for "tiffy"
SearchResult<TestEntity> res1 = idx.search(new String[] { FIELD }, "tiffy", null);
Assert.assertNotNull(res1);
Assert.assertEquals(0, res1.getResultCount());
Assert.assertNotNull(res1.getResult());
Assert.assertEquals(0, res1.getResult().size());
// now change entity value from "bob" to "tiffy" and update the index
entity1.setValue("tiffy"); //$NON-NLS-1$
idx.update(Collections.singleton(entity1));
// check there is now a hit for "tiffy"
SearchResult<TestEntity> res2 = idx.search(new String[] { FIELD }, "tiffy", null);
Assert.assertNotNull(res2);
Assert.assertEquals(1, res2.getResultCount());
Assert.assertNotNull(res2.getResult());
Assert.assertEquals(1, res2.getResult().size());
Assert.assertEquals("tiffy", res2.getResult().get(0).getEntity().getValue());
Assert.assertEquals("tiffy", res2.getResult().get(0).getValue(FIELD, false));
Assert.assertEquals("<em>tiffy</em>", res2.getResult().get(0).getValue(FIELD, true));
// verify that "bob" is not found anymore
SearchResult<TestEntity> res3 = idx.search(new String[] { FIELD }, "bob", null);
Assert.assertNotNull(res3);
Assert.assertEquals(0, res3.getResultCount());
Assert.assertNotNull(res3.getResult());
Assert.assertEquals(0, res3.getResult().size());
}
@Test
public void testUpdate_deleted() throws Exception {
// first ensure there is a hit for "bob"
SearchResult<TestEntity> res1 = idx.search(new String[] { FIELD }, "bob", null);
Assert.assertNotNull(res1);
Assert.assertEquals(1, res1.getResultCount());
Assert.assertNotNull(res1.getResult());
Assert.assertEquals(1, res1.getResult().size());
// mark "bob" as deleted and update the index
entity1.setDeleted(true);
idx.update(Collections.singleton(entity1));
// verify that "bob" is not found anymore
SearchResult<TestEntity> res3 = idx.search(new String[] { FIELD }, "bob", null);
Assert.assertNotNull(res3);
Assert.assertEquals(0, res3.getResultCount());
Assert.assertNotNull(res3.getResult());
Assert.assertEquals(0, res3.getResult().size());
}
@Test
public void testMoreLikeThis() throws Exception {
SearchResult<TestEntity> res1 = idx.moreLikeThis(entity2, new String[] { FIELD }, 5);
Assert.assertNotNull(res1);
Assert.assertEquals(3, res1.getResultCount());
Assert.assertEquals(3, res1.getResult().size());
Assert.assertEquals(entity3.getValue(), res1.getResult().get(0).getEntity().getValue());
Assert.assertEquals(entity4.getValue(), res1.getResult().get(1).getEntity().getValue());
Assert.assertEquals(entity5.getValue(), res1.getResult().get(2).getEntity().getValue());
SearchResult<TestEntity> res2 = idx.moreLikeThis(entity2, new String[] { FIELD }, 2);
Assert.assertNotNull(res2);
Assert.assertEquals(3, res2.getResultCount());
Assert.assertEquals(2, res2.getResult().size());
Assert.assertEquals(entity3.getValue(), res2.getResult().get(0).getEntity().getValue());
Assert.assertEquals(entity4.getValue(), res2.getResult().get(1).getEntity().getValue());
}
@Test
public void testFacetedSearch() throws Exception {
FacetedSearchResult<TestEntity> res = idx.facetedSearch(new String[] { FIELD }, new String[] { FACET },
"alice", null); //$NON-NLS-1$
Assert.assertNotNull(res);
Assert.assertEquals(4, res.getResultCount());
Assert.assertNotNull(res.getResult());
Assert.assertEquals(4, res.getResult().size());
Map<String, Integer> map = res.getFacetInfo().get(FACET);
Assert.assertNotNull(map);
Assert.assertEquals(Integer.valueOf(2), map.get("sentence"));
Assert.assertEquals(Integer.valueOf(1), map.get("fullname"));
Assert.assertEquals(Integer.valueOf(1), map.get("firstname"));
}
@Test
public void testGetExtendedQuery() throws Exception {
Assert.assertEquals("(\"foobar\" foobar* foobar~)", LuceneIndex.getExtendedQuery("foobar"));
Assert.assertEquals("(\"foo\" foo* foo~) (\"bar\" bar* bar~)", LuceneIndex.getExtendedQuery("foo bar"));
Assert.assertEquals("foobar*", LuceneIndex.getExtendedQuery("foobar*"));
Assert.assertEquals("foobar~", LuceneIndex.getExtendedQuery("foobar~"));
Assert.assertEquals("foobar~0.8", LuceneIndex.getExtendedQuery("foobar~0.8"));
Assert.assertEquals("foo*bar", LuceneIndex.getExtendedQuery("foo*bar"));
Assert.assertEquals("foo?bar", LuceneIndex.getExtendedQuery("foo?bar"));
Assert.assertEquals("+foobar", LuceneIndex.getExtendedQuery("+foobar"));
Assert.assertEquals("-foobar", LuceneIndex.getExtendedQuery("-foobar"));
Assert.assertEquals("+foobar (\"foobar\" foobar* foobar~)", LuceneIndex.getExtendedQuery("+foobar foobar"));
Assert.assertEquals("\"foobar\"", LuceneIndex.getExtendedQuery("\"foobar\""));
Assert.assertEquals("\"foobar\"~10", LuceneIndex.getExtendedQuery("\"foobar\"~10"));
Assert.assertEquals("\"foo\"^3 \"bar\"", LuceneIndex.getExtendedQuery("\"foo\"^3 \"bar\""));
Assert.assertEquals("(foobar)", LuceneIndex.getExtendedQuery("(foobar)"));
Assert.assertEquals("[foobar]", LuceneIndex.getExtendedQuery("[foobar]"));
Assert.assertEquals("{foobar}", LuceneIndex.getExtendedQuery("{foobar}"));
Assert.assertEquals(")foobar(", LuceneIndex.getExtendedQuery(")foobar("));
Assert.assertEquals(")foo bar(", LuceneIndex.getExtendedQuery(")foo bar("));
Assert.assertEquals("(\"foobar\")", LuceneIndex.getExtendedQuery("(\"foobar\")"));
Assert.assertEquals("(foobar) (\"foobar\" foobar* foobar~)",
LuceneIndex.getExtendedQuery("(foobar) foobar"));
Assert.assertEquals("(\"foo\" foo* foo~) (foo OR bar) (\"bar\" bar* bar~)",
LuceneIndex.getExtendedQuery("foo (foo OR bar) bar"));
Assert.assertEquals("\"foobar\" (\"foobar\" foobar* foobar~)",
LuceneIndex.getExtendedQuery("\"foobar\" foobar"));
Assert.assertEquals("title:\"foo\" AND text:bar",
LuceneIndex.getExtendedQuery("title:\"foo\" AND text:bar"));
// (uppercase) "AND" is a Lucene keyword , but (lowercase) "and" is not !
Assert.assertEquals("title:\"foo\" (\"and\" and* and~) text:bar",
LuceneIndex.getExtendedQuery("title:\"foo\" and text:bar"));
Assert.assertEquals("title:\"foo\" OR (\"foobar\" foobar* foobar~) NOT text:bar",
LuceneIndex.getExtendedQuery("title:\"foo\" OR foobar NOT text:bar"));
Assert.assertEquals("title:foo (\"bar\" bar* bar~)",
LuceneIndex.getExtendedQuery("title:foo bar"));
Assert.assertEquals("title:[foo TO bar]",
LuceneIndex.getExtendedQuery("title:[foo TO bar]"));
Assert.assertEquals("title:(+foo +\"\bar\")",
LuceneIndex.getExtendedQuery("title:(+foo +\"\bar\")"));
}
}