From 943a9b215efeb9699edc9e0123b5c489ee23c9aa Mon Sep 17 00:00:00 2001 From: Fabian Steeg Date: Tue, 22 Aug 2017 14:04:33 +0200 Subject: [PATCH] Set up index tests and custom query method in IndexComponent See https://github.com/hbz/lobid-authorities/issues/20 --- app/controllers/HomeController.java | 10 ++----- app/modules/IndexComponent.java | 31 +++++++++++++++++++- test/modules/IndexTest.java | 45 +++++++++++++++++++++++++++-- test/ttl/1045328480.ttl | 37 ++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 12 deletions(-) create mode 100644 test/ttl/1045328480.ttl diff --git a/app/controllers/HomeController.java b/app/controllers/HomeController.java index b4461e2..82fdba6 100644 --- a/app/controllers/HomeController.java +++ b/app/controllers/HomeController.java @@ -17,11 +17,8 @@ import org.apache.jena.atlas.web.HttpException; import org.elasticsearch.action.get.GetResponse; -import org.elasticsearch.action.search.SearchRequestBuilder; import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.aggregations.Aggregation; -import org.elasticsearch.search.aggregations.AggregationBuilders; import org.elasticsearch.search.aggregations.bucket.terms.Terms; import org.elasticsearch.search.aggregations.bucket.terms.Terms.Bucket; @@ -51,7 +48,7 @@ */ public class HomeController extends Controller { - private static final String TYPE = "type"; + public static final String TYPE = "type"; @Inject Environment env; @@ -146,10 +143,7 @@ public Result gnd(String id) { } public Result search(String q, int from, int size, String format) { - SearchRequestBuilder requestBuilder = index.client().prepareSearch(config("index.name")) - .setQuery(QueryBuilders.queryStringQuery(q)).setFrom(from).setSize(size); - requestBuilder.addAggregation(AggregationBuilders.terms(TYPE).field(TYPE + ".raw").size(1000)); - SearchResponse response = requestBuilder.get(); + SearchResponse response = index.query(q, from, size); response().setHeader("Access-Control-Allow-Origin", "*"); return format.equals("html") ? htmlSearch(q, from, size, format, response) : ok(returnAsJson(q, response)).as(config("index.content")); diff --git a/app/modules/IndexComponent.java b/app/modules/IndexComponent.java index 2f03875..09a4149 100644 --- a/app/modules/IndexComponent.java +++ b/app/modules/IndexComponent.java @@ -23,20 +23,34 @@ import org.elasticsearch.action.admin.indices.refresh.RefreshRequest; import org.elasticsearch.action.bulk.BulkRequestBuilder; import org.elasticsearch.action.bulk.BulkResponse; +import org.elasticsearch.action.search.SearchRequestBuilder; +import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.Client; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.index.query.MatchQueryBuilder; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.index.query.QueryStringQueryBuilder; import org.elasticsearch.node.Node; import org.elasticsearch.node.internal.InternalSettingsPreparer; import org.elasticsearch.plugins.Plugin; +import org.elasticsearch.search.aggregations.AggregationBuilders; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import controllers.HomeController; import play.Logger; import play.inject.ApplicationLifecycle; public interface IndexComponent { Client client(); + + SearchResponse query(String q, int from, int size); + + public default SearchResponse query(String q) { + return query(q, 0, 10); + } } class EmbeddedIndex implements IndexComponent { @@ -86,7 +100,8 @@ private void startup() { indexData(client, pathToJson, indexName); } } else { - Logger.info("Index exists. Delete the 'data/' directory to reindexfrom " + pathToJson); + Logger.info("Index exists. Delete the '" + config("index.home") + "/data' directory to reindex from " + + pathToJson); } if (new File(pathToUpdates).exists()) { Logger.info("Indexing updates from " + pathToUpdates); @@ -178,4 +193,18 @@ private static void executeBulk(int pendingIndexRequests) { } Logger.info("Indexed {} docs, took: {}", pendingIndexRequests, bulkResponse.getTook()); } + + @Override + public SearchResponse query(String q, int from, int size) { + MatchQueryBuilder preferredName = QueryBuilders.matchQuery("preferredName", q).boost(2); + QueryStringQueryBuilder queryStringQuery = QueryBuilders.queryStringQuery(q); + QueryBuilder query = QueryBuilders.boolQuery().should(preferredName).must(queryStringQuery) + .minimumNumberShouldMatch(0); + SearchRequestBuilder requestBuilder = client().prepareSearch(config("index.name")).setQuery(query).setFrom(from) + .setSize(size); + requestBuilder.addAggregation( + AggregationBuilders.terms(HomeController.TYPE).field(HomeController.TYPE + ".raw").size(1000)); + SearchResponse response = requestBuilder.get(); + return response; + } } \ No newline at end of file diff --git a/test/modules/IndexTest.java b/test/modules/IndexTest.java index 7617d19..391421b 100644 --- a/test/modules/IndexTest.java +++ b/test/modules/IndexTest.java @@ -5,8 +5,10 @@ import java.io.FileWriter; import java.io.IOException; +import org.elasticsearch.action.search.SearchResponse; import org.junit.AfterClass; import org.junit.Assert; +import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -15,26 +17,33 @@ import com.hp.hpl.jena.rdf.model.ModelFactory; import apps.Convert; +import models.AuthorityResource; import play.Application; +import play.api.inject.BindingKey; +import play.api.inject.DefaultApplicationLifecycle; import play.inject.guice.GuiceApplicationBuilder; import play.libs.Json; import play.test.WithApplication; public class IndexTest extends WithApplication { + private static final File[] TEST_FILES = new File("test/ttl").listFiles(); private static final String PATH = "GND.jsonl"; + private IndexComponent index; + @Override protected Application provideApplication() { // See // https://www.playframework.com/documentation/2.6.1/JavaDependencyInjection + // https://www.playframework.com/documentation/2.6.x/JavaTestingWithGuice return new GuiceApplicationBuilder().build(); } @BeforeClass public static void convert() throws IOException { try (FileWriter out = new FileWriter(PATH)) { - for (File file : new File("test/ttl").listFiles()) { + for (File file : TEST_FILES) { Model sourceModel = ModelFactory.createDefaultModel(); sourceModel.read(new FileReader(file), null, "TTL"); String id = file.getName().split("\\.")[0]; @@ -50,14 +59,44 @@ public static void convert() throws IOException { @AfterClass public static void cleanup() throws IOException { // TODO: use separate dir, override config in provideApplication + // https://www.playframework.com/documentation/2.6.x/JavaTestingWithGuice#configuration // FileUtils.deleteDirectory(new File("data")); } + @Before + public void setup() { + app.injector().instanceOf(DefaultApplicationLifecycle.class).stop(); + index = app.injector().instanceOf(new BindingKey<>(IndexComponent.class)); + } + @Test - public void test() { + public void testIndexData() { Assert.assertTrue("Index data file should exist", new File(PATH).exists()); System.out.println("Indexed from: " + PATH); - // TODO: inject index, check number of docs + } + + @Test + public void testTotalHits() { + Assert.assertEquals(TEST_FILES.length, index.query("*").getHits().getTotalHits()); + } + + @Test + public void testFieldQuery() { + Assert.assertEquals(1, index.query("preferredName:\"Weizenbaum, Joseph\"").getHits().getTotalHits()); + Assert.assertEquals(0, index.query("id:\"Weizenbaum, Joseph\"").getHits().getTotalHits()); + } + + @Test + public void testContextQuery() { + Assert.assertEquals(0, index.query("jsonld").getHits().getTotalHits()); + } + + @Test + public void testPerfectFieldMatch() { + SearchResponse response = index.query("london"); + Assert.assertEquals(2, response.getHits().getTotalHits()); + Assert.assertEquals("London", Json.fromJson(Json.parse(response.getHits().getHits()[0].getSourceAsString()), + AuthorityResource.class).preferredName.get(0)); } } diff --git a/test/ttl/1045328480.ttl b/test/ttl/1045328480.ttl new file mode 100644 index 0000000..77692d2 --- /dev/null +++ b/test/ttl/1045328480.ttl @@ -0,0 +1,37 @@ +@prefix schema: . +@prefix gndo: . +@prefix lib: . +@prefix marcRole: . +@prefix owl: . +@prefix skos: . +@prefix dcmitype: . +@prefix rdfs: . +@prefix geo: . +@prefix umbel: . +@prefix dbp: . +@prefix dnbt: . +@prefix rdau: . +@prefix sf: . +@prefix dnb_intern: . +@prefix rdf: . +@prefix v: . +@prefix dcterms: . +@prefix bibo: . +@prefix gbv: . +@prefix isbd: . +@prefix foaf: . +@prefix dc: . + + a gndo:BuildingOrMemorial ; + foaf:page ; + gndo:gndIdentifier "1045328480" ; + gndo:architect , ; + gndo:broaderTermInstantial ; + gndo:gndSubjectCategory ; + gndo:geographicAreaCode ; + gndo:definition "72-stöckiges u. 310 m hohes, multifunktionales Hochhaus am Südufer d. Themse i.d. Nähe d. London Bridge in London-Southwark"@de ; + gndo:dateOfProduction "16.03.2009-01.02.2013" ; + gndo:variantNameForThePlaceOrGeographicName "London Bridge Tower (London)" , "Shard London Bridge (London)" , "Shard of Glass (London)" , "32 London Bridge (London)" , "Thirty-two London Bridge (London)" ; + gndo:preferredNameForThePlaceOrGeographicName "The Shard (London)" ; + gndo:place . +