Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
58 changes: 30 additions & 28 deletions .vscode/cspell.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

{
"version": "0.2",
"language": "en",
Expand Down Expand Up @@ -463,40 +462,43 @@
"filename": "sdk/search/azure-search-documents/**",
"words": [
"ADLS",
"mysearch",
"TFIDF",
"Decompounder",
"NGRAM",
"adlsgen",
"AICLIP",
"AICLIPIMAGE",
"AISERVICES",
"AITOKENS",
"Bangla",
"Rslp",
"vectorizer",
"vectorizable",
"vectorizers",
"hnsw",
"rerank",
"reranker",
"mytext",
"myocr",
"econo",
"azsearch",
"bokmaal",
"Bokm",
"bokmal",
"adlsgen",
"sorani",
"mylocation",
"myloc",
"coffe",
"dari",
"Decompounder",
"econo",
"hitel",
"AISERVICES",
"AICLIP",
"TLARGE",
"TBASE",
"TGIANT",
"tiktoken",
"AITOKENS",
"hnsw",
"kstem",
"Matryoshka",
"mylocation",
"myloc",
"myocr",
"mysearch",
"mytext",
"NGRAM",
"OMINI",
"resyncing"
"rerank",
"reranker",
"resyncing",
"Rslp",
"sorani",
"TBASE",
"TFIDF",
"tiktoken",
"TGIANT",
"TLARGE",
"vectorizable",
"vectorizer",
"vectorizers"
]
},
{
Expand Down
2 changes: 1 addition & 1 deletion eng/versioning/version_client.txt
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ com.azure:azure-monitor-query-perf;1.0.0-beta.1;1.0.0-beta.1
com.azure:azure-openrewrite;1.0.0-beta.1;1.0.0-beta.1
com.azure:azure-perf-test-parent;1.0.0-beta.1;1.0.0-beta.1
com.azure:azure-quantum-jobs;1.0.0-beta.1;1.0.0-beta.2
com.azure:azure-search-documents;11.8.1;11.9.0-beta.2
com.azure:azure-search-documents;11.8.1;12.0.0-beta.1
com.azure:azure-search-perf;1.0.0-beta.1;1.0.0-beta.1
com.azure:azure-security-attestation;1.1.38;1.2.0-beta.1
com.azure:azure-security-confidentialledger;1.0.34;1.1.0-beta.2
Expand Down
2 changes: 1 addition & 1 deletion sdk/search/azure-search-documents/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Release History

## 11.9.0-beta.2 (Unreleased)
## 12.0.0-beta.1 (Unreleased)

### Features Added

Expand Down
77 changes: 38 additions & 39 deletions sdk/search/azure-search-documents/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -316,11 +316,9 @@ Let's explore them with a search for a "luxury" hotel.
enumerate over the results, and extract data using `SearchDocument`'s dictionary indexer.

```java readme-sample-searchWithDynamicType
for (SearchResult searchResult : SEARCH_CLIENT.search("luxury")) {
SearchDocument doc = searchResult.getDocument(SearchDocument.class);
String id = (String) doc.get("hotelId");
String name = (String) doc.get("hotelName");
System.out.printf("This is hotelId %s, and this is hotel name %s.%n", id, name);
for (SearchResult searchResult : SEARCH_CLIENT.search(new SearchOptions().setSearchText("luxury"))) {
Map<String, Object> doc = searchResult.getAdditionalProperties();
System.out.printf("This is hotelId %s, and this is hotel name %s.%n", doc.get("HotelId"), doc.get("HotelName"));
}
```

Expand All @@ -330,9 +328,7 @@ Define a `Hotel` class.

```java readme-sample-hotelclass
public static class Hotel {
@SimpleField(isKey = true, isFilterable = true, isSortable = true)
private String id;
@SearchableField(isFilterable = true, isSortable = true)
private String name;

public String getId() {
Expand All @@ -358,11 +354,9 @@ public static class Hotel {
Use it in place of `SearchDocument` when querying.

```java readme-sample-searchWithStronglyType
for (SearchResult searchResult : SEARCH_CLIENT.search("luxury")) {
Hotel doc = searchResult.getDocument(Hotel.class);
String id = doc.getId();
String name = doc.getName();
System.out.printf("This is hotelId %s, and this is hotel name %s.%n", id, name);
for (SearchResult searchResult : SEARCH_CLIENT.search(new SearchOptions().setSearchText("luxury"))) {
Map<String, Object> doc = searchResult.getAdditionalProperties();
System.out.printf("This is hotelId %s, and this is hotel name %s.%n", doc.get("Id"), doc.get("Name"));
}
```

Expand All @@ -375,11 +369,11 @@ The `SearchOptions` provide powerful control over the behavior of our queries.
Let's search for the top 5 luxury hotels with a good rating.

```java readme-sample-searchWithSearchOptions
SearchOptions options = new SearchOptions()
SearchOptions options = new SearchOptions().setSearchText("luxury")
.setFilter("rating ge 4")
.setOrderBy("rating desc")
.setTop(5);
SearchPagedIterable searchResultsIterable = SEARCH_CLIENT.search("luxury", options, Context.NONE);
SearchPagedIterable searchResultsIterable = SEARCH_CLIENT.search(options);
// ...
```

Expand All @@ -394,58 +388,56 @@ There are multiple ways of preparing search fields for a search index. For basic
to configure the field of model class.

```java readme-sample-createIndexUseFieldBuilder
List<SearchField> searchFields = SearchIndexClient.buildSearchFields(Hotel.class, null);
List<SearchField> searchFields = SearchIndexClient.buildSearchFields(Hotel.class);
SEARCH_INDEX_CLIENT.createIndex(new SearchIndex("index", searchFields));
```

For advanced scenarios, we can build search fields using `SearchField` directly.

```java readme-sample-createIndex
List<SearchField> searchFieldList = new ArrayList<>();
searchFieldList.add(new SearchField("hotelId", SearchFieldDataType.STRING)
searchFieldList.add(new SearchField("HotelId", SearchFieldDataType.STRING)
.setKey(true)
.setFilterable(true)
.setSortable(true));

searchFieldList.add(new SearchField("hotelName", SearchFieldDataType.STRING)
searchFieldList.add(new SearchField("HotelName", SearchFieldDataType.STRING)
.setSearchable(true)
.setFilterable(true)
.setSortable(true));
searchFieldList.add(new SearchField("description", SearchFieldDataType.STRING)
searchFieldList.add(new SearchField("Description", SearchFieldDataType.STRING)
.setSearchable(true)
.setAnalyzerName(LexicalAnalyzerName.EU_LUCENE));
searchFieldList.add(new SearchField("tags", SearchFieldDataType.collection(SearchFieldDataType.STRING))
searchFieldList.add(new SearchField("Tags", SearchFieldDataType.collection(SearchFieldDataType.STRING))
.setSearchable(true)
.setFilterable(true)
.setFacetable(true));
searchFieldList.add(new SearchField("address", SearchFieldDataType.COMPLEX)
.setFields(new SearchField("streetAddress", SearchFieldDataType.STRING).setSearchable(true),
new SearchField("city", SearchFieldDataType.STRING)
searchFieldList.add(new SearchField("Address", SearchFieldDataType.COMPLEX)
.setFields(new SearchField("StreetAddress", SearchFieldDataType.STRING).setSearchable(true),
new SearchField("City", SearchFieldDataType.STRING)
.setSearchable(true)
.setFilterable(true)
.setFacetable(true)
.setSortable(true),
new SearchField("stateProvince", SearchFieldDataType.STRING)
new SearchField("StateProvince", SearchFieldDataType.STRING)
.setSearchable(true)
.setFilterable(true)
.setFacetable(true)
.setSortable(true),
new SearchField("country", SearchFieldDataType.STRING)
new SearchField("Country", SearchFieldDataType.STRING)
.setSearchable(true)
.setFilterable(true)
.setFacetable(true)
.setSortable(true),
new SearchField("postalCode", SearchFieldDataType.STRING)
new SearchField("PostalCode", SearchFieldDataType.STRING)
.setSearchable(true)
.setFilterable(true)
.setFacetable(true)
.setSortable(true)
));
.setSortable(true)));

// Prepare suggester.
SearchSuggester suggester = new SearchSuggester("sg", Collections.singletonList("hotelName"));
SearchSuggester suggester = new SearchSuggester("sg", "hotelName");
// Prepare SearchIndex with index name and search fields.
SearchIndex index = new SearchIndex("hotels").setFields(searchFieldList).setSuggesters(suggester);
SearchIndex index = new SearchIndex("hotels", searchFieldList).setSuggesters(suggester);
// Create an index
SEARCH_INDEX_CLIENT.createIndex(index);
```
Expand All @@ -457,8 +449,8 @@ your index if you already know the key. You could get the key from a query, for
information about it or navigate your customer to that document.

```java readme-sample-retrieveDocuments
Hotel hotel = SEARCH_CLIENT.getDocument("1", Hotel.class);
System.out.printf("This is hotelId %s, and this is hotel name %s.%n", hotel.getId(), hotel.getName());
Map<String, Object> hotel = SEARCH_CLIENT.getDocument("1").getAdditionalProperties();
System.out.printf("This is hotelId %s, and this is hotel name %s.%n", hotel.get("Id"), hotel.get("Name"));
```

### Adding documents to your index
Expand All @@ -468,9 +460,16 @@ There are [a few special rules for merging](https://learn.microsoft.com/rest/api
to be aware of.

```java readme-sample-batchDocumentsOperations
IndexDocumentsBatch<Hotel> batch = new IndexDocumentsBatch<>();
batch.addUploadActions(Collections.singletonList(new Hotel().setId("783").setName("Upload Inn")));
batch.addMergeActions(Collections.singletonList(new Hotel().setId("12").setName("Renovated Ranch")));
Map<String, Object> hotel = new LinkedHashMap<>();
hotel.put("Id", "783");
hotel.put("Name", "Upload Inn");

Map<String, Object> hotel2 = new LinkedHashMap<>();
hotel2.put("Id", "12");
hotel2.put("Name", "Renovated Ranch");
IndexDocumentsBatch batch = new IndexDocumentsBatch(
new IndexAction().setActionType(IndexActionType.UPLOAD).setAdditionalProperties(hotel),
new IndexAction().setActionType(IndexActionType.MERGE).setAdditionalProperties(hotel2));
SEARCH_CLIENT.indexDocuments(batch);
```

Expand All @@ -484,10 +483,10 @@ The examples so far have been using synchronous APIs, but we provide full suppor
to use [SearchAsyncClient](#create-a-searchclient).

```java readme-sample-searchWithAsyncClient
SEARCH_ASYNC_CLIENT.search("luxury")
SEARCH_ASYNC_CLIENT.search(new SearchOptions().setSearchText("luxury"))
.subscribe(result -> {
Hotel hotel = result.getDocument(Hotel.class);
System.out.printf("This is hotelId %s, and this is hotel name %s.%n", hotel.getId(), hotel.getName());
Map<String, Object> hotel = result.getAdditionalProperties();
System.out.printf("This is hotelId %s, and this is hotel name %s.%n", hotel.get("Id"), hotel.get("Name"));
});
```

Expand Down Expand Up @@ -528,7 +527,7 @@ Any Search API operation that fails will throw an [`HttpResponseException`][Http

```java readme-sample-handleErrorsWithSyncClient
try {
Iterable<SearchResult> results = SEARCH_CLIENT.search("hotel");
Iterable<SearchResult> results = SEARCH_CLIENT.search(new SearchOptions().setSearchText("hotel"));
} catch (HttpResponseException ex) {
// The exception contains the HTTP status code and the detailed message
// returned from the search service
Expand Down
2 changes: 1 addition & 1 deletion sdk/search/azure-search-documents/assets.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
"AssetsRepo": "Azure/azure-sdk-assets",
"AssetsRepoPrefixPath": "java",
"TagPrefix": "java/search/azure-search-documents",
"Tag": "java/search/azure-search-documents_3eb1fda9ef"
"Tag": "java/search/azure-search-documents_9febe9224e"
}
11 changes: 5 additions & 6 deletions sdk/search/azure-search-documents/checkstyle-suppressions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@
<!-- This file is generated by the /eng/scripts/linting_suppression_generator.py script. -->

<suppressions>
<suppress files="com.azure.search.documents.knowledgebases.SearchKnowledgeBaseAsyncClient.java" checks="JavadocPackageCheck" />
<suppress files="com.azure.search.documents.test.environment.models.Book.java" checks="MemberNameCheck" />
<suppress files="com.azure.search.documents.test.environment.models.LoudHotel.java" checks="MemberNameCheck" />
<suppress files="com.azure.search.documents.test.environment.models.Book.java" checks="MethodNameCheck" />
<suppress files="com.azure.search.documents.test.environment.models.LoudHotel.java" checks="MethodNameCheck" />
<suppress files="com.azure.search.documents.test.environment.models.Book.java" checks="ParameterNameCheck" />
<suppress files="com.azure.search.documents.testingmodels.Book.java" checks="MemberNameCheck" />
<suppress files="com.azure.search.documents.testingmodels.LoudHotel.java" checks="MemberNameCheck" />
<suppress files="com.azure.search.documents.testingmodels.Book.java" checks="MethodNameCheck" />
<suppress files="com.azure.search.documents.testingmodels.LoudHotel.java" checks="MethodNameCheck" />
<suppress files="com.azure.search.documents.testingmodels.Book.java" checks="ParameterNameCheck" />
<suppress files="com.azure.search.documents.indexes.FieldBuilderTests.java" checks="VisibilityModifierCheck" />
<suppress files="com.azure.search.documents.SearchClientBuilder.java" checks="io.clientcore.linting.extensions.checkstyle.checks.ServiceClientBuilderCheck" />
<suppress files="com.azure.search.documents.SearchIndexingBufferedAsyncSender.java" checks="io.clientcore.linting.extensions.checkstyle.checks.ServiceClientCheck" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import com.azure.autorest.customization.ClassCustomization;
import com.azure.autorest.customization.Customization;
import com.azure.autorest.customization.LibraryCustomization;
import com.azure.autorest.customization.PackageCustomization;
import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.ast.Modifier;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.BodyDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.nodeTypes.NodeWithMembers;
import org.slf4j.Logger;

import java.util.Arrays;

/**
* Contains customizations for Azure AI Search code generation.
*/
public class SearchCustomizations extends Customization {
@Override
public void customize(LibraryCustomization libraryCustomization, Logger logger) {
PackageCustomization documents = libraryCustomization.getPackage("com.azure.search.documents");
PackageCustomization indexes = libraryCustomization.getPackage("com.azure.search.documents.indexes");
PackageCustomization knowledge = libraryCustomization.getPackage("com.azure.search.documents.knowledgebases");

hideGeneratedSearchApis(documents);

addSearchAudienceScopeHandling(documents.getClass("SearchClientBuilder"), logger);
addSearchAudienceScopeHandling(indexes.getClass("SearchIndexClientBuilder"), logger);
addSearchAudienceScopeHandling(indexes.getClass("SearchIndexerClientBuilder"), logger);
addSearchAudienceScopeHandling(knowledge.getClass("KnowledgeBaseRetrievalClientBuilder"), logger);
}

// Weird quirk in the Java generator where SearchOptions is inferred from the parameters of searchPost in TypeSpec,
// where that class doesn't actually exist in TypeSpec so it requires making the searchPost API public which we
// don't want. This customization hides the searchPost APIs that were exposed.
private static void hideGeneratedSearchApis(PackageCustomization documents) {
for (String className : Arrays.asList("SearchClient", "SearchAsyncClient")) {
documents.getClass(className).customizeAst(ast -> ast.getClassByName(className).ifPresent(clazz -> {
clazz.getMethodsByName("searchWithResponse")
.stream()
.filter(method -> method.isAnnotationPresent("Generated"))
.forEach(MethodDeclaration::setModifiers);

clazz.getMethodsByName("autocompleteWithResponse")
.stream()
.filter(method -> method.isAnnotationPresent("Generated"))
.forEach(MethodDeclaration::setModifiers);

clazz.getMethodsByName("suggestWithResponse")
.stream()
.filter(method -> method.isAnnotationPresent("Generated"))
.forEach(MethodDeclaration::setModifiers);
Comment thread
alzimmermsft marked this conversation as resolved.
}));
}
}

// Adds SearchAudience handling to generated builders. This is a temporary fix until
// https://github.com/microsoft/typespec/issues/9458 is addressed.
private static void addSearchAudienceScopeHandling(ClassCustomization customization, Logger logger) {
customization.customizeAst(ast -> ast.getClassByName(customization.getClassName()).ifPresent(clazz -> {
// Make sure 'DEFAULT_SCOPES' exists before adding instance level 'scopes'
if (clazz.getMembers().stream().noneMatch(declaration -> declaration.isFieldDeclaration()
&& "DEFAULT_SCOPES".equals(declaration.asFieldDeclaration().getVariable(0).getNameAsString()))) {
logger.info(
"Client builder didn't contain field 'DEFAULT_SCOPES', skipping adding support for SearchAudience");
return;
}

// Add mutable instance 'String[] scopes' with an initialized value of 'DEFAULT_SCOPES'. Also, add the
// Generated annotation so this will get cleaned up automatically in the future when the TypeSpec issue is
// resolved.
clazz.addMember(new FieldDeclaration().setModifiers(Modifier.Keyword.PRIVATE)
.addMarkerAnnotation("Generated")
.addVariable(new VariableDeclarator().setName("scopes").setType("String[]")
.setInitializer("DEFAULT_SCOPES")));

// Get the 'createHttpPipeline' method and change the 'BearerTokenAuthenticationPolicy' to use 'scopes'
// instead of 'DEFAULT_SCOPES' when creating the object.
clazz.getMethodsByName("createHttpPipeline").forEach(method -> method.getBody().ifPresent(body ->
method.setBody(StaticJavaParser.parseBlock(body.toString().replace("DEFAULT_SCOPES", "scopes")))));
Comment thread
alzimmermsft marked this conversation as resolved.
}));
}
}
Loading
Loading