diff --git a/retail/interactive-tutorials/pom.xml b/retail/interactive-tutorials/pom.xml new file mode 100644 index 00000000000..c8dd8e57ce4 --- /dev/null +++ b/retail/interactive-tutorials/pom.xml @@ -0,0 +1,69 @@ + + + 4.0.0 + com.google.cloud + retail-interactive-tutorials + jar + Google Cloud Retail Interactive Tutorials + https://github.com/googleapis/java-retail + + + + com.google.cloud.samples + shared-configuration + 1.2.0 + + + + 1.8 + 1.8 + UTF-8 + + + + + com.google.cloud + google-cloud-retail + 2.0.6 + + + junit + junit + 4.13.2 + test + + + com.google.cloud + google-cloud-bigquery + 2.5.1 + + + com.google.cloud + google-cloud-storage + 2.2.2 + + + com.google.code.gson + gson + 2.8.9 + + + + + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + + false + + + + + \ No newline at end of file diff --git a/retail/interactive-tutorials/src/main/java/search/SearchWithFiltering.java b/retail/interactive-tutorials/src/main/java/search/SearchWithFiltering.java new file mode 100644 index 00000000000..11e70e5f187 --- /dev/null +++ b/retail/interactive-tutorials/src/main/java/search/SearchWithFiltering.java @@ -0,0 +1,72 @@ +/* + * Copyright 2022 Google LLC + * + * 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. + */ + +// [START retail_search_for_products_with_filter] + +/* + * Call Retail API to search for a products in a catalog, + * filter the results by different product fields. + */ + +package search; + +import com.google.cloud.retail.v2.SearchRequest; +import com.google.cloud.retail.v2.SearchResponse; +import com.google.cloud.retail.v2.SearchServiceClient; +import java.io.IOException; +import java.util.UUID; + +public class SearchWithFiltering { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String projectId = System.getenv("PROJECT_ID"); + String defaultCatalogName = + String.format("projects/%s/locations/global/catalogs/default_catalog", projectId); + String defaultSearchPlacementName = defaultCatalogName + "/placements/default_search"; + + getSearchResponse(defaultSearchPlacementName); + } + + public static SearchResponse getSearchResponse(String defaultSearchPlacementName) + throws IOException { + // TRY DIFFERENT FILTER EXPRESSIONS HERE: + String filter = "(colorFamilies: ANY(\"Black\"))"; + String queryPhrase = "Tee"; + int pageSize = 10; + String visitorId = UUID.randomUUID().toString(); + + SearchRequest searchRequest = + SearchRequest.newBuilder() + .setPlacement(defaultSearchPlacementName) + .setVisitorId(visitorId) + .setQuery(queryPhrase) + .setPageSize(pageSize) + .setFilter(filter) + .build(); + + System.out.println("Search request: " + searchRequest); + + try (SearchServiceClient client = SearchServiceClient.create()) { + SearchResponse searchResponse = client.search(searchRequest).getPage().getResponse(); + System.out.println("Search response: " + searchResponse); + + return searchResponse; + } + } +} + +// [END retail_search_for_products_with_filter] diff --git a/retail/interactive-tutorials/src/main/java/search/SearchWithOrdering.java b/retail/interactive-tutorials/src/main/java/search/SearchWithOrdering.java new file mode 100644 index 00000000000..82b43a99bd6 --- /dev/null +++ b/retail/interactive-tutorials/src/main/java/search/SearchWithOrdering.java @@ -0,0 +1,71 @@ +/* + * Copyright 2022 Google LLC + * + * 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. + */ + +// [START retail_search_for_products_with_ordering] + +/* + * Call Retail API to search for a products in a catalog, + * order the results by different product fields. + */ + +package search; + +import com.google.cloud.retail.v2.SearchRequest; +import com.google.cloud.retail.v2.SearchResponse; +import com.google.cloud.retail.v2.SearchServiceClient; +import java.io.IOException; +import java.util.UUID; + +public class SearchWithOrdering { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String projectId = System.getenv("PROJECT_ID"); + String defaultCatalogName = + String.format("projects/%s/locations/global/catalogs/default_catalog", projectId); + String defaultSearchPlacementName = defaultCatalogName + "/placements/default_search"; + + getSearchResponse(defaultSearchPlacementName); + } + + public static SearchResponse getSearchResponse(String defaultSearchPlacementName) + throws IOException { + // TRY DIFFERENT ORDER BY EXPRESSION HERE: + String order = "price desc"; + String queryPhrase = "Hoodie"; + int pageSize = 10; + String visitorId = UUID.randomUUID().toString(); + + SearchRequest searchRequest = + SearchRequest.newBuilder() + .setPlacement(defaultSearchPlacementName) + .setQuery(queryPhrase) + .setOrderBy(order) + .setVisitorId(visitorId) + .setPageSize(pageSize) + .build(); + System.out.println("Search request: " + searchRequest); + + try (SearchServiceClient client = SearchServiceClient.create()) { + SearchResponse searchResponse = client.search(searchRequest).getPage().getResponse(); + System.out.println("Search response: " + searchResponse); + + return searchResponse; + } + } +} + +// [END retail_search_for_products_with_ordering] diff --git a/retail/interactive-tutorials/src/main/java/search/SearchWithPagination.java b/retail/interactive-tutorials/src/main/java/search/SearchWithPagination.java new file mode 100644 index 00000000000..6a7d270ecc4 --- /dev/null +++ b/retail/interactive-tutorials/src/main/java/search/SearchWithPagination.java @@ -0,0 +1,78 @@ +/* + * Copyright 2022 Google LLC + * + * 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. + */ + +// [START retail_search_for_products_with_page_size] + +/* + * Call Retail API to search for a products in a catalog, + * limit the number of the products per page and go to the next page + * using "next_page_token" or jump to chosen page using "offset". + */ + +package search; + +import com.google.cloud.retail.v2.SearchRequest; +import com.google.cloud.retail.v2.SearchResponse; +import com.google.cloud.retail.v2.SearchServiceClient; +import java.io.IOException; +import java.util.UUID; + +public class SearchWithPagination { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String projectId = System.getenv("PROJECT_ID"); + String defaultCatalogName = + String.format("projects/%s/locations/global/catalogs/default_catalog", projectId); + String defaultSearchPlacementName = defaultCatalogName + "/placements/default_search"; + + getSearchResponse(defaultSearchPlacementName); + } + + public static SearchResponse getSearchResponse(String defaultSearchPlacementName) + throws IOException { + // TRY DIFFERENT PAGINATION PARAMETERS HERE: + int pageSize = 6; + String queryPhrase = "Hoodie"; + int offset = 0; + String pageToken = ""; + String visitorId = UUID.randomUUID().toString(); + + SearchRequest searchRequest = + SearchRequest.newBuilder() + .setPlacement(defaultSearchPlacementName) + .setVisitorId(visitorId) + .setQuery(queryPhrase) + .setPageSize(pageSize) + .setOffset(offset) + .setPageToken(pageToken) + .build(); + System.out.println("Search request: " + searchRequest); + + try (SearchServiceClient client = SearchServiceClient.create()) { + SearchResponse searchResponseFirstPage = client.search(searchRequest).getPage().getResponse(); + System.out.println("Search response: " + searchResponseFirstPage); + + // PASTE CALL WITH NEXT PAGE TOKEN HERE: + + // PASTE CALL WITH OFFSET HERE: + + return searchResponseFirstPage; + } + } +} + +// [END retail_search_for_products_with_page_size] diff --git a/retail/interactive-tutorials/src/main/java/search/SearchWithQueryExpansionSpec.java b/retail/interactive-tutorials/src/main/java/search/SearchWithQueryExpansionSpec.java new file mode 100644 index 00000000000..30275d39092 --- /dev/null +++ b/retail/interactive-tutorials/src/main/java/search/SearchWithQueryExpansionSpec.java @@ -0,0 +1,77 @@ +/* + * Copyright 2022 Google LLC + * + * 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. + */ + +// [START retail_search_for_products_with_query_expansion_specification] + +/* + * Call Retail API to search for a products in a catalog, + * enabling the query expansion feature to let the Google Retail Search + * build an automatic query expansion. + */ + +package search; + +import com.google.cloud.retail.v2.SearchRequest; +import com.google.cloud.retail.v2.SearchRequest.QueryExpansionSpec; +import com.google.cloud.retail.v2.SearchRequest.QueryExpansionSpec.Condition; +import com.google.cloud.retail.v2.SearchResponse; +import com.google.cloud.retail.v2.SearchServiceClient; +import java.io.IOException; +import java.util.UUID; + +public class SearchWithQueryExpansionSpec { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String projectId = System.getenv("PROJECT_ID"); + String defaultCatalogName = + String.format("projects/%s/locations/global/catalogs/default_catalog", projectId); + String defaultSearchPlacementName = defaultCatalogName + "/placements/default_search"; + + getSearchResponse(defaultSearchPlacementName); + } + + public static SearchResponse getSearchResponse(String defaultSearchPlacementName) + throws IOException { + // TRY DIFFERENT QUERY EXPANSION CONDITION HERE: + Condition condition = Condition.AUTO; + int pageSize = 10; + String queryPhrase = "Google Youth Hero Tee Grey"; + String visitorId = UUID.randomUUID().toString(); + + QueryExpansionSpec queryExpansionSpec = + QueryExpansionSpec.newBuilder().setCondition(condition).build(); + + SearchRequest searchRequest = + SearchRequest.newBuilder() + .setPlacement(defaultSearchPlacementName) + .setQuery(queryPhrase) + .setVisitorId(visitorId) + .setQueryExpansionSpec(queryExpansionSpec) + .setPageSize(pageSize) + .build(); + System.out.println("Search request: " + searchRequest); + + try (SearchServiceClient client = SearchServiceClient.create()) { + SearchResponse searchResponse = client.search(searchRequest).getPage().getResponse(); + System.out.println("Search response: " + searchResponse); + + return searchResponse; + } + } +} + +// [END retail_search_for_products_with_query_expansion_specification] diff --git a/retail/interactive-tutorials/src/test/java/search/SearchWithFilteringTest.java b/retail/interactive-tutorials/src/test/java/search/SearchWithFilteringTest.java new file mode 100644 index 00000000000..5c8401d5188 --- /dev/null +++ b/retail/interactive-tutorials/src/test/java/search/SearchWithFilteringTest.java @@ -0,0 +1,67 @@ +/* + * Copyright 2022 Google LLC + * + * 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. + */ + +package search; + +import com.google.cloud.retail.v2.SearchResponse; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import util.StreamGobbler; + +public class SearchWithFilteringTest { + + private String output; + private String defaultSearchPlacementName; + + @Before + public void setUp() throws IOException, InterruptedException, ExecutionException { + String projectId = System.getenv("PROJECT_ID"); + String defaultCatalogName = + String.format("projects/%s/locations/global/catalogs/default_catalog", projectId); + defaultSearchPlacementName = defaultCatalogName + "/placements/default_search"; + + Process exec = + Runtime.getRuntime() + .exec("mvn compile exec:java -Dexec.mainClass=search.SearchWithFiltering"); + StreamGobbler streamGobbler = new StreamGobbler(exec.getInputStream()); + Future stringFuture = Executors.newSingleThreadExecutor().submit(streamGobbler); + + output = stringFuture.get(); + } + + @Test + public void testOutput() { + Assert.assertTrue(output.matches("(?s)^(.*Search request.*)$")); + Assert.assertTrue(output.matches("(?s)^(.*Search response.*)$")); + Assert.assertTrue(output.matches("(?s)^(.*results.*id.*)$")); + } + + @Test + public void TestSearchWithFiltering() throws IOException { + SearchResponse response = SearchWithFiltering.getSearchResponse(defaultSearchPlacementName); + Assert.assertEquals(10, response.getResultsCount()); + String productTitle = response.getResults(0).getProduct().getTitle(); + Assert.assertTrue(productTitle.contains("Google Black Cloud Tee")); + Assert.assertTrue( + response.getResults(0).getProduct().getColorInfo().getColorFamilies(0).contains("Black")); + Assert.assertEquals(16, response.getTotalSize()); + } +} diff --git a/retail/interactive-tutorials/src/test/java/search/SearchWithOrderingTest.java b/retail/interactive-tutorials/src/test/java/search/SearchWithOrderingTest.java new file mode 100644 index 00000000000..80244c192d8 --- /dev/null +++ b/retail/interactive-tutorials/src/test/java/search/SearchWithOrderingTest.java @@ -0,0 +1,65 @@ +/* + * Copyright 2022 Google LLC + * + * 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. + */ + +package search; + +import com.google.cloud.retail.v2.SearchResponse; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import util.StreamGobbler; + +public class SearchWithOrderingTest { + + private String output; + private String defaultSearchPlacementName; + + @Before + public void setUp() throws IOException, InterruptedException, ExecutionException { + String projectId = System.getenv("PROJECT_ID"); + String defaultCatalogName = + String.format("projects/%s/locations/global/catalogs/default_catalog", projectId); + defaultSearchPlacementName = defaultCatalogName + "/placements/default_search"; + + Process exec = + Runtime.getRuntime() + .exec("mvn compile exec:java -Dexec.mainClass=search.SearchWithOrdering"); + StreamGobbler streamGobbler = new StreamGobbler(exec.getInputStream()); + Future stringFuture = Executors.newSingleThreadExecutor().submit(streamGobbler); + + output = stringFuture.get(); + } + + @Test + public void testOutput() { + Assert.assertTrue(output.matches("(?s)^(.*Search request.*)$")); + Assert.assertTrue(output.matches("(?s)^(.*Search response.*)$")); + Assert.assertTrue(output.matches("(?s)^(.*results.*id.*)$")); + } + + @Test + public void TestSearchWithOrdering() throws IOException { + SearchResponse response = SearchWithOrdering.getSearchResponse(defaultSearchPlacementName); + Assert.assertEquals(10, response.getResultsCount()); + String productTitle = response.getResults(3).getProduct().getTitle(); + Assert.assertTrue(productTitle.contains("Hoodie")); + Assert.assertEquals(39, response.getResults(0).getProduct().getPriceInfo().getPrice(), 0); + } +} diff --git a/retail/interactive-tutorials/src/test/java/search/SearchWithPaginationTest.java b/retail/interactive-tutorials/src/test/java/search/SearchWithPaginationTest.java new file mode 100644 index 00000000000..9b618ccd485 --- /dev/null +++ b/retail/interactive-tutorials/src/test/java/search/SearchWithPaginationTest.java @@ -0,0 +1,63 @@ +/* + * Copyright 2022 Google LLC + * + * 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. + */ + +package search; + +import com.google.cloud.retail.v2.SearchResponse; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import util.StreamGobbler; + +public class SearchWithPaginationTest { + private String output; + private String defaultSearchPlacementName; + + @Before + public void setUp() throws IOException, InterruptedException, ExecutionException { + String projectId = System.getenv("PROJECT_ID"); + String defaultCatalogName = + String.format("projects/%s/locations/global/catalogs/default_catalog", projectId); + defaultSearchPlacementName = defaultCatalogName + "/placements/default_search"; + + Process exec = + Runtime.getRuntime() + .exec("mvn compile exec:java -Dexec.mainClass=search.SearchWithPagination"); + StreamGobbler streamGobbler = new StreamGobbler(exec.getInputStream()); + Future stringFuture = Executors.newSingleThreadExecutor().submit(streamGobbler); + + output = stringFuture.get(); + } + + @Test + public void testOutput() { + Assert.assertTrue(output.matches("(?s)^(.*Search request.*)$")); + Assert.assertTrue(output.matches("(?s)^(.*Search response.*)$")); + Assert.assertTrue(output.matches("(?s)^(.*results.*id.*)$")); + } + + @Test + public void TestSearchWithOrdering() throws IOException { + SearchResponse response = SearchWithPagination.getSearchResponse(defaultSearchPlacementName); + String productTitle = response.getResults(0).getProduct().getTitle(); + Assert.assertTrue(productTitle.contains("Hoodie")); + Assert.assertEquals(6, response.getResultsCount()); + } +} diff --git a/retail/interactive-tutorials/src/test/java/search/SearchWithQueryExpansionSpecTest.java b/retail/interactive-tutorials/src/test/java/search/SearchWithQueryExpansionSpecTest.java new file mode 100644 index 00000000000..ce91e06a55f --- /dev/null +++ b/retail/interactive-tutorials/src/test/java/search/SearchWithQueryExpansionSpecTest.java @@ -0,0 +1,68 @@ +/* + * Copyright 2022 Google LLC + * + * 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. + */ + +package search; + +import com.google.cloud.retail.v2.SearchResponse; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import util.StreamGobbler; + +public class SearchWithQueryExpansionSpecTest { + + private String output; + private String defaultSearchPlacementName; + + @Before + public void setUp() throws IOException, InterruptedException, ExecutionException { + String projectId = System.getenv("PROJECT_ID"); + String defaultCatalogName = + String.format("projects/%s/locations/global/catalogs/default_catalog", projectId); + defaultSearchPlacementName = defaultCatalogName + "/placements/default_search"; + + Process exec = + Runtime.getRuntime() + .exec("mvn compile exec:java -Dexec.mainClass=search.SearchWithQueryExpansionSpec"); + StreamGobbler streamGobbler = new StreamGobbler(exec.getInputStream()); + Future stringFuture = Executors.newSingleThreadExecutor().submit(streamGobbler); + + output = stringFuture.get(); + } + + @Test + public void testOutput() { + Assert.assertTrue(output.matches("(?s)^(.*Search request.*)$")); + Assert.assertTrue(output.matches("(?s)^(.*Search response.*)$")); + Assert.assertTrue(output.matches("(?s)^(.*results.*id.*)$")); + } + + @Test + public void testSearchWithQueryExpansionSpec() throws IOException { + SearchResponse response = + SearchWithQueryExpansionSpec.getSearchResponse(defaultSearchPlacementName); + Assert.assertEquals(10, response.getResultsCount()); + Assert.assertTrue( + response.getResults(0).getProduct().getTitle().contains("Google Youth Hero Tee Grey")); + Assert.assertFalse( + response.getResults(2).getProduct().getTitle().contains("Google Youth Hero Tee Grey")); + Assert.assertTrue(response.getQueryExpansionInfo().getExpandedQuery()); + } +} diff --git a/retail/interactive-tutorials/src/test/java/util/StreamGobbler.java b/retail/interactive-tutorials/src/test/java/util/StreamGobbler.java new file mode 100644 index 00000000000..a9c3c3a795b --- /dev/null +++ b/retail/interactive-tutorials/src/test/java/util/StreamGobbler.java @@ -0,0 +1,40 @@ +/* + * Copyright 2022 Google LLC + * + * 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. + */ + +package util; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.stream.Collectors; + +public class StreamGobbler implements Callable { + + private final InputStream inputStream; + + public StreamGobbler(InputStream inputStream) { + this.inputStream = inputStream; + } + + @Override + public String call() { + List stringList = + new BufferedReader(new InputStreamReader(inputStream)).lines().collect(Collectors.toList()); + return String.join("\n", stringList); + } +}