From 7914f1fe5b3e7e0e73534fb800315a6b55622f6d Mon Sep 17 00:00:00 2001 From: Kristian Aune Date: Tue, 13 Jun 2017 12:51:11 +0200 Subject: Sample app for handler and searcher - first cut, not properly tested yet --- sample-apps/http-api-using-searcher/README.md | 4 + sample-apps/http-api-using-searcher/feed.json | 14 ++++ sample-apps/http-api-using-searcher/pom.xml | 85 ++++++++++++++++++++++ .../main/application/searchdefinitions/basic.sd | 16 ++++ .../src/main/application/services.xml | 55 ++++++++++++++ .../main/java/com/yahoo/demo/DemoComponent.java | 45 ++++++++++++ .../src/main/java/com/yahoo/demo/DemoHandler.java | 50 +++++++++++++ .../src/main/java/com/yahoo/demo/DemoRenderer.java | 74 +++++++++++++++++++ .../src/main/java/com/yahoo/demo/DemoSearcher.java | 76 +++++++++++++++++++ .../src/main/resources/configdefinitions/demo.def | 5 ++ .../java/com/yahoo/example/ApplicationMain.java | 27 +++++++ sample-apps/pom.xml | 4 + 12 files changed, 455 insertions(+) create mode 100644 sample-apps/http-api-using-searcher/README.md create mode 100644 sample-apps/http-api-using-searcher/feed.json create mode 100644 sample-apps/http-api-using-searcher/pom.xml create mode 100644 sample-apps/http-api-using-searcher/src/main/application/searchdefinitions/basic.sd create mode 100644 sample-apps/http-api-using-searcher/src/main/application/services.xml create mode 100644 sample-apps/http-api-using-searcher/src/main/java/com/yahoo/demo/DemoComponent.java create mode 100644 sample-apps/http-api-using-searcher/src/main/java/com/yahoo/demo/DemoHandler.java create mode 100644 sample-apps/http-api-using-searcher/src/main/java/com/yahoo/demo/DemoRenderer.java create mode 100644 sample-apps/http-api-using-searcher/src/main/java/com/yahoo/demo/DemoSearcher.java create mode 100644 sample-apps/http-api-using-searcher/src/main/resources/configdefinitions/demo.def create mode 100644 sample-apps/http-api-using-searcher/src/test/java/com/yahoo/example/ApplicationMain.java diff --git a/sample-apps/http-api-using-searcher/README.md b/sample-apps/http-api-using-searcher/README.md new file mode 100644 index 00000000000..6511db54b7e --- /dev/null +++ b/sample-apps/http-api-using-searcher/README.md @@ -0,0 +1,4 @@ +# Vespa sample applications - Building a HTTP API using a searcher + +Refer to search/handler-tutorial.html for documentation FIXME real link soon + diff --git a/sample-apps/http-api-using-searcher/feed.json b/sample-apps/http-api-using-searcher/feed.json new file mode 100644 index 00000000000..bbd91c314de --- /dev/null +++ b/sample-apps/http-api-using-searcher/feed.json @@ -0,0 +1,14 @@ +[ + { + "put": "id:test:basic::http://demo/0/", + "fields": { + "description": "red hat smurf demo" + } + }, + { + "put": "id:test:basic::http://demo/1/", + "fields": { + "description": "red smurf hat demo something" + } + } +] diff --git a/sample-apps/http-api-using-searcher/pom.xml b/sample-apps/http-api-using-searcher/pom.xml new file mode 100644 index 00000000000..7ae8549c385 --- /dev/null +++ b/sample-apps/http-api-using-searcher/pom.xml @@ -0,0 +1,85 @@ + + + + 4.0.0 + com.yahoo.demo + sample-app + 1.0.1 + container-plugin + + + UTF-8 + true + 6-SNAPSHOT + + + + + junit + junit + 4.11 + test + + + com.yahoo.vespa + application + ${vespa_version} + test + + + com.yahoo.vespa + container-dev + ${vespa_version} + provided + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.1 + + true + true + true + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.19.1 + + + true + + ${test.hide} + + + + com.yahoo.vespa + vespa-application-maven-plugin + ${vespa_version} + + + + packageApplication + + + + + + com.yahoo.vespa + bundle-plugin + ${vespa_version} + true + + + + diff --git a/sample-apps/http-api-using-searcher/src/main/application/searchdefinitions/basic.sd b/sample-apps/http-api-using-searcher/src/main/application/searchdefinitions/basic.sd new file mode 100644 index 00000000000..3c4920a1912 --- /dev/null +++ b/sample-apps/http-api-using-searcher/src/main/application/searchdefinitions/basic.sd @@ -0,0 +1,16 @@ +search basic { + + document basic { + + field description type string { + indexing: summary | index + } + + } + + fieldset default { + fields: description + } + +} + diff --git a/sample-apps/http-api-using-searcher/src/main/application/services.xml b/sample-apps/http-api-using-searcher/src/main/application/services.xml new file mode 100644 index 00000000000..fe16ec42260 --- /dev/null +++ b/sample-apps/http-api-using-searcher/src/main/application/services.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + smurf + + + + + + + + + + http://*:8080/demo + + + + + + + + + + + 1 + + + + + + + + + + + 1 + + + + + diff --git a/sample-apps/http-api-using-searcher/src/main/java/com/yahoo/demo/DemoComponent.java b/sample-apps/http-api-using-searcher/src/main/java/com/yahoo/demo/DemoComponent.java new file mode 100644 index 00000000000..2182cebecb9 --- /dev/null +++ b/sample-apps/http-api-using-searcher/src/main/java/com/yahoo/demo/DemoComponent.java @@ -0,0 +1,45 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.demo; + +import com.yahoo.component.AbstractComponent; + +import java.text.Normalizer; +import java.util.HashSet; +import java.util.Random; +import java.util.Set; + +/** + * A shared component with an "expensive" constructor exposing a shared, + * thread-safe service. + */ +public class DemoComponent extends AbstractComponent { + private final Set illegalHashes; + + public DemoComponent() { + illegalHashes = new HashSet(); + Random r = new Random(); + // generate up to 1e6 unique hashes + for (int i = 0; i < 1000 * 1000; ++i) { + illegalHashes.add(r.nextInt()); + } + } + + /** + * NFKC-normalize term, or replace it with "smurf" with a low probability. + * Will change choice for each run, but will be constant in a single run of + * the container. + * + * @param term + * term to normalize or replace with "smurf" + * @return NFKC-normalized term or "smurf" + */ + public String normalize(String term) { + String normalized = Normalizer.normalize(term, Normalizer.Form.NFKC); + if (illegalHashes.contains(normalized.hashCode())) { + return "smurf"; + } else { + return normalized; + } + } + +} diff --git a/sample-apps/http-api-using-searcher/src/main/java/com/yahoo/demo/DemoHandler.java b/sample-apps/http-api-using-searcher/src/main/java/com/yahoo/demo/DemoHandler.java new file mode 100644 index 00000000000..cf14f6d58cd --- /dev/null +++ b/sample-apps/http-api-using-searcher/src/main/java/com/yahoo/demo/DemoHandler.java @@ -0,0 +1,50 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.demo; + +import com.google.inject.Inject; +import com.yahoo.container.jdisc.HttpRequest; +import com.yahoo.container.jdisc.HttpResponse; +import com.yahoo.container.jdisc.LoggingRequestHandler; +import com.yahoo.container.logging.AccessLog; +import com.yahoo.search.handler.SearchHandler; +import com.yahoo.search.query.Model; +import com.yahoo.search.query.Presentation; + +import java.util.concurrent.Executor; + +/** + * Forward requests to search handler after adding "Red Hat" as query and "demo" + * as renderer ID. + */ +public class DemoHandler extends LoggingRequestHandler { + + private final SearchHandler searchHandler; + + /** + * Constructor for use in injection. The requested objects are subclasses of + * component or have dedicated providers, so the container will know how to + * create this handler. + * + * @param executor + * threadpool, provided by Vespa + * @param accessLog + * access log for incoming queries, provided by Vespa + * @param searchHandler + * the Vespa search handler, also automatically injected + */ + @Inject + public DemoHandler(Executor executor, AccessLog accessLog, + SearchHandler searchHandler) { + super(executor, accessLog, null, true); + this.searchHandler = searchHandler; + } + + @Override + public HttpResponse handle(HttpRequest request) { + HttpRequest searchRequest = new HttpRequest.Builder(request) + .put(Model.QUERY_STRING, "Red Hat") + .put(Presentation.FORMAT, "demo").createDirectRequest(); + HttpResponse r = searchHandler.handle(searchRequest); + return r; + } +} diff --git a/sample-apps/http-api-using-searcher/src/main/java/com/yahoo/demo/DemoRenderer.java b/sample-apps/http-api-using-searcher/src/main/java/com/yahoo/demo/DemoRenderer.java new file mode 100644 index 00000000000..979c50f7f8f --- /dev/null +++ b/sample-apps/http-api-using-searcher/src/main/java/com/yahoo/demo/DemoRenderer.java @@ -0,0 +1,74 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.demo; + +import com.yahoo.search.Result; +import com.yahoo.search.rendering.Renderer; +import com.yahoo.search.result.Hit; +import com.yahoo.search.result.HitGroup; + +import java.io.IOException; +import java.io.Writer; +import java.util.Iterator; + +/** + * Render result sets as plain text. First line is whether an error occurred, + * second rendering initialization time stamp, then each line is the ID of each + * document returned, and the last line is time stamp for when the renderer was + * finished. + */ +public class DemoRenderer extends Renderer { + private String heading; + + /** + * No global, shared state to set. + */ + public DemoRenderer() { + } + + @Override + protected void render(Writer writer, Result result) throws IOException { + if (result.hits().getErrorHit() == null) { + writer.write("OK\n"); + } else { + writer.write("Oops!\n"); + } + writer.write(heading); + writer.write("\n"); + renderHits(writer, result.hits()); + writer.write("Rendering finished work: " + System.currentTimeMillis()); + writer.write("\n"); + } + + private void renderHits(Writer writer, HitGroup hits) throws IOException { + for (Iterator i = hits.deepIterator(); i.hasNext();) { + Hit h = i.next(); + if (h.types().contains("summary")) { + String id = h.getDisplayId(); + if (id != null) { + writer.write(id); + writer.write("\n"); + } + } + } + } + + @Override + public String getEncoding() { + return "utf-8"; + } + + @Override + public String getMimeType() { + return "text/plain"; + } + + /** + * Initialize mutable, per-result set state here. + */ + @Override + public void init() { + long time = System.currentTimeMillis(); + heading = "Renderer initialized: " + time; + } + +} diff --git a/sample-apps/http-api-using-searcher/src/main/java/com/yahoo/demo/DemoSearcher.java b/sample-apps/http-api-using-searcher/src/main/java/com/yahoo/demo/DemoSearcher.java new file mode 100644 index 00000000000..e749a3c1556 --- /dev/null +++ b/sample-apps/http-api-using-searcher/src/main/java/com/yahoo/demo/DemoSearcher.java @@ -0,0 +1,76 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.demo; + +import com.yahoo.component.chain.dependencies.After; +import com.yahoo.component.chain.dependencies.Before; +import com.yahoo.component.chain.dependencies.Provides; +import com.yahoo.demo.DemoConfig.Demo; +import com.yahoo.prelude.query.AndItem; +import com.yahoo.prelude.query.CompositeItem; +import com.yahoo.prelude.query.Item; +import com.yahoo.prelude.query.WordItem; +import com.yahoo.processing.request.CompoundName; +import com.yahoo.search.Query; +import com.yahoo.search.Result; +import com.yahoo.search.Searcher; +import com.yahoo.search.query.QueryTree; +import com.yahoo.search.searchchain.Execution; +import com.yahoo.search.searchchain.PhaseNames; + +import java.util.List; + +/** + * A searcher for adding a set of configured terms as AND terms, and add a + * single term from the request to the query tree (after running the term + * through a shared component). + */ +@After(PhaseNames.RAW_QUERY) +@Before(PhaseNames.TRANSFORMED_QUERY) +@Provides(DemoSearcher.DEMO_TRANSFORM) +public class DemoSearcher extends Searcher { + public static final String DEMO_TRANSFORM = "com.yahoo.demo.DemoSearcher.NothingUseful"; + + /** + * The request property with this name will be filtered and added to the + * query as an AND term. + */ + public static final CompoundName EXTRA_TERM = new CompoundName("extraTerm"); + + private final List extraTerms; + + private final DemoComponent infrastructure; + + public DemoSearcher(DemoComponent infrastructure, DemoConfig extraTerms) { + this.extraTerms = extraTerms.demo(); + this.infrastructure = infrastructure; + } + + /** + * Programmatic query transform, add terms from config and the EXTRA_TERM + * request property. + */ + @Override + public Result search(Query query, Execution execution) { + QueryTree q = query.getModel().getQueryTree(); + addAndItem(q, infrastructure.normalize( + query.properties().getString(EXTRA_TERM))); + for (Demo d : extraTerms) { + addAndItem(q, d.term()); + } + return execution.search(query); + } + + private void addAndItem(QueryTree q, String term) { + Item root = q.getRoot(); + CompositeItem compositeRoot; + if (root instanceof AndItem) { + compositeRoot = (CompositeItem) root; + } else { + compositeRoot = new AndItem(); + compositeRoot.addItem(root); + q.setRoot(compositeRoot); + } + compositeRoot.addItem(new WordItem(term)); + } + +} diff --git a/sample-apps/http-api-using-searcher/src/main/resources/configdefinitions/demo.def b/sample-apps/http-api-using-searcher/src/main/resources/configdefinitions/demo.def new file mode 100644 index 00000000000..9a804089433 --- /dev/null +++ b/sample-apps/http-api-using-searcher/src/main/resources/configdefinitions/demo.def @@ -0,0 +1,5 @@ +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +namespace=demo + +demo[].term string + diff --git a/sample-apps/http-api-using-searcher/src/test/java/com/yahoo/example/ApplicationMain.java b/sample-apps/http-api-using-searcher/src/test/java/com/yahoo/example/ApplicationMain.java new file mode 100644 index 00000000000..da85e486602 --- /dev/null +++ b/sample-apps/http-api-using-searcher/src/test/java/com/yahoo/example/ApplicationMain.java @@ -0,0 +1,27 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.example; + +import com.yahoo.application.Networking; +import org.junit.Test; + +import java.nio.file.FileSystems; + +import static org.junit.Assume.assumeTrue; + +public class ApplicationMain { + + @Test + public void runFromMaven() throws Exception { + assumeTrue(Boolean.valueOf(System.getProperty("isMavenSurefirePlugin"))); + main(null); + } + + public static void main(String[] args) throws Exception { + try (com.yahoo.application.Application app = com.yahoo.application.Application.fromApplicationPackage( + FileSystems.getDefault().getPath("src/main/application"), + Networking.enable)) { + app.getClass(); // throws NullPointerException + Thread.sleep(Long.MAX_VALUE); + } + } +} \ No newline at end of file diff --git a/sample-apps/pom.xml b/sample-apps/pom.xml index 1114ff2ec4b..91d1b7c7580 100644 --- a/sample-apps/pom.xml +++ b/sample-apps/pom.xml @@ -13,5 +13,9 @@ basic-search-java blog-recommendation boolean-search + -- cgit v1.2.3