feat(retail): add Vertex AI Search for commerce snippets#10252
feat(retail): add Vertex AI Search for commerce snippets#10252alarconesparza wants to merge 4 commits intoGoogleCloudPlatform:mainfrom
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces Java code samples for Vertex AI Search for commerce, covering basic search, pagination, and offset functionalities, along with corresponding integration tests. The review feedback identifies several improvement opportunities: using getTotalSize() instead of getResultsCount() to ensure accurate result counts across pages, simplifying API response handling, and removing redundant output in the samples. Additionally, the feedback suggests optimizing resource management in test utilities by reusing service clients instead of recreating them within loops.
| .build(); | ||
| SearchPagedResponse response = searchServiceClient.search(searchRequest); | ||
|
|
||
| return response.getPage().getResponse().getResultsCount(); |
There was a problem hiding this comment.
This method currently returns the number of results on the first page (limited by setPageSize(2)). If the number of products to test is greater than 2, the condition in waitForProductsToBeIndexed will never be met, causing potential test failures or unnecessary delays. Use getTotalSize() to get the total count of matching products.
| return response.getPage().getResponse().getResultsCount(); | |
| return response.getResponse().getTotalSize(); |
| .build(); | ||
| SearchPagedResponse response = searchServiceClient.search(searchRequest); | ||
|
|
||
| SearchResponse searchResponse = response.getPage().getResponse(); |
There was a problem hiding this comment.
The expression response.getPage().getResponse() can be simplified to response.getResponse(). The SearchPagedResponse object provides direct access to the underlying SearchResponse message.
| SearchResponse searchResponse = response.getPage().getResponse(); | |
| SearchResponse searchResponse = response.getResponse(); |
References
- For code samples, conventions may allow for practices that favor simplicity and clarity.
|
|
||
| SearchResponse searchResponse = response.getPage().getResponse(); | ||
|
|
||
| System.out.println("Found " + searchResponse.getResultsCount() + " results"); |
There was a problem hiding this comment.
Using getResultsCount() only returns the number of items on the current page (limited by pageSize). To show the total number of products matching the query across all pages, use getTotalSize() instead.
| System.out.println("Found " + searchResponse.getResultsCount() + " results"); | |
| System.out.println("Found " + searchResponse.getTotalSize() + " results"); |
References
- For code samples, conventions may allow for practices that favor simplicity and clarity.
|
|
||
| SearchResponse searchResponse = response.getPage().getResponse(); | ||
|
|
||
| System.out.println("Found " + searchResponse.getResultsCount() + " results"); |
There was a problem hiding this comment.
Using getResultsCount() returns the number of items in the current response, which is limited by the page size and doesn't reflect the total matches. Use getTotalSize() to display the total number of matching products.
| System.out.println("Found " + searchResponse.getResultsCount() + " results"); | |
| System.out.println("Found " + searchResponse.getTotalSize() + " results"); |
References
- For code samples, conventions may allow for practices that favor simplicity and clarity.
| System.out.println("\nResults of page number " + currentPage + ":"); | ||
| System.out.println("Found " + page.getResponse().getResultsCount() + " results"); | ||
| for (SearchResult searchResult : page.getResponse().getResultsList()) { | ||
| System.out.println("Search Result: \n" + searchResult); |
There was a problem hiding this comment.
Printing the entire searchResult protobuf object is redundant and creates very noisy output, especially since the product name is already printed below. Consider removing this line to keep the output clean.
References
- For code samples, conventions may allow for practices that favor simplicity and clarity.
| public static void deleteProduct(String productName) throws IOException { | ||
| DeleteProductRequest deleteProductRequest = | ||
| DeleteProductRequest.newBuilder().setName(productName).build(); | ||
|
|
||
| try (ProductServiceClient serviceClient = ProductServiceClient.create()) { | ||
| serviceClient.deleteProduct(deleteProductRequest); | ||
| } | ||
| } |
| public static int amountOfProductsReadyToTest(String projectId, String query) throws IOException { | ||
| try (SearchServiceClient searchServiceClient = SearchServiceClient.create()) { | ||
| ServingConfigName servingConfigName = | ||
| ServingConfigName.of(projectId, "global", "default_catalog", "default_search"); | ||
| BranchName branchName = | ||
| BranchName.of(projectId, "global", "default_catalog", "default_branch"); | ||
| SearchRequest searchRequest = | ||
| SearchRequest.newBuilder() | ||
| .setPlacement(servingConfigName.toString()) | ||
| .setBranch(branchName.toString()) | ||
| .setVisitorId("test_visitor") | ||
| .setQuery(query) | ||
| .setPageSize(2) | ||
| .build(); | ||
| SearchPagedResponse response = searchServiceClient.search(searchRequest); | ||
|
|
||
| return response.getPage().getResponse().getResultsCount(); | ||
| } | ||
| } |
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces Java code samples and integration tests for Vertex AI Search for commerce, covering basic search, pagination, and offset functionality. The feedback provided focuses on correcting an inaccurate description in the README, optimizing the POM file by leveraging the BOM for dependency management, and improving the efficiency and reliability of test utilities by reusing service clients and extending the indexing wait times to prevent flaky tests.
|
|
||
| ## Samples | ||
|
|
||
| - **[Search.java](src/main/java/com/example/search/Search.java)**: Basic search request showing both text search and browse search (using categories). |
There was a problem hiding this comment.
The description for Search.java is inaccurate. It states that the sample shows "both text search and browse search (using categories)", but the implementation in Search.java only demonstrates a basic text search using the query parameter. It does not include any category-based filtering or browsing logic.
| <dependency> | ||
| <groupId>com.google.cloud</groupId> | ||
| <artifactId>google-cloud-retail</artifactId> | ||
| <version>2.93.0</version> | ||
| </dependency> |
There was a problem hiding this comment.
Since you are using the libraries-bom in the dependencyManagement section, you should omit the explicit version for google-cloud-retail. This allows the BOM to manage the version, ensuring compatibility across different Google Cloud libraries and avoiding potential dependency conflicts.
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-retail</artifactId>
</dependency>
| DeleteProductRequest deleteProductRequest = | ||
| DeleteProductRequest.newBuilder().setName(productName).build(); | ||
|
|
||
| try (ProductServiceClient serviceClient = ProductServiceClient.create()) { |
There was a problem hiding this comment.
Creating a ProductServiceClient for every single product deletion is inefficient. Since this method is called in a loop during test cleanup (e.g., in SearchIT.tearDown), consider refactoring the code to reuse a single client instance for all deletions. While Rule 5 allows for simpler patterns in samples, efficiency in test helpers is important to avoid resource exhaustion.
References
- For code samples, conventions may allow for practices that are not production-ready in favor of simplicity and clarity.
|
|
||
| public static boolean areProductsReadyToTest(String projectId, String query, int amountOfProducts) | ||
| throws IOException { | ||
| try (SearchServiceClient searchServiceClient = SearchServiceClient.create()) { |
There was a problem hiding this comment.
Creating a SearchServiceClient is an expensive operation. Since areProductsReadyToTest is called repeatedly within a loop in waitForProductsToBeIndexed, creating a new client on every iteration is inefficient. You should create the client once and reuse it. While Rule 5 allows for simpler patterns in samples, efficiency in test helpers is important to avoid resource exhaustion.
References
- For code samples, conventions may allow for practices that are not production-ready in favor of simplicity and clarity.
| public static void waitForProductsToBeIndexed( | ||
| String projectId, List<Product> products, String productTitle) | ||
| throws InterruptedException, IOException { | ||
| for (int i = 0; i < 3; i++) { |
There was a problem hiding this comment.
The current retry logic only attempts to check for indexed products 3 times with a 10-second delay (total 30 seconds). In Vertex AI Search for commerce, indexing new products can often take several minutes. This short timeout is likely to cause flaky tests in real-world scenarios. Consider increasing the number of retries or the wait interval.
Description
Fixes internal b/502616950
Note: Before submitting a pull request, please open an issue for discussion if you are not associated with Google.
Checklist
pom.xmlparent set to latestshared-configurationmvn clean verifyrequiredmvn -P lint checkstyle:checkrequiredmvn -P lint clean compile pmd:cpd-check spotbugs:checkadvisory only