Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Search synonym map #11590

Merged
merged 7 commits into from
May 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sdk/search/azure-search-documents/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

- Reorganized `SearchServiceClient` into `SearchIndexClient` & `SearchIndexerClient` #11507
- Split searchindex.json and searchservice.json models and operations into separate namespaces #11508
- Now Search Synonym Map creation/update returns a model #11514

## 1.0.0b3 (2020-05-04)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------
import msrest.serialization
from ._generated.models import LexicalAnalyzer, LexicalTokenizer


Expand Down Expand Up @@ -87,3 +88,108 @@ def __init__(self, **kwargs):
self.pattern = kwargs.get("pattern", r"\W+")
self.flags = kwargs.get("flags", None)
self.group = kwargs.get("group", -1)


class SearchResourceEncryptionKey(msrest.serialization.Model):
"""A customer-managed encryption key in Azure Key Vault. Keys that you create and manage can be
used to encrypt or decrypt data-at-rest in Azure Cognitive Search, such as indexes and synonym maps.

All required parameters must be populated in order to send to Azure.

:param key_name: Required. The name of your Azure Key Vault key to be used to encrypt your data
at rest.
:type key_name: str
:param key_version: Required. The version of your Azure Key Vault key to be used to encrypt
your data at rest.
:type key_version: str
:param vault_uri: Required. The URI of your Azure Key Vault, also referred to as DNS name, that
contains the key to be used to encrypt your data at rest. An example URI might be https://my-
keyvault-name.vault.azure.net.
:type vault_uri: str
:param application_id: Required. An AAD Application ID that was granted the required access
permissions to the Azure Key Vault that is to be used when encrypting your data at rest. The
Application ID should not be confused with the Object ID for your AAD Application.
:type application_id: str
:param application_secret: The authentication key of the specified AAD application.
:type application_secret: str
"""

_validation = {
'key_name': {'required': True},
'key_version': {'required': True},
'vault_uri': {'required': True},
}

_attribute_map = {
'key_name': {'key': 'keyVaultKeyName', 'type': 'str'},
'key_version': {'key': 'keyVaultKeyVersion', 'type': 'str'},
'vault_uri': {'key': 'keyVaultUri', 'type': 'str'},
'application_id': {'key': 'applicationId', 'type': 'str'},
'application_secret': {'key': 'applicationSecret', 'type': 'str'},
}

def __init__(
self,
**kwargs
):
super(SearchResourceEncryptionKey, self).__init__(**kwargs)
self.key_name = kwargs['key_name']
self.key_version = kwargs['key_version']
self.vault_uri = kwargs['vault_uri']
self.application_id = kwargs.get('application_id', None)
self.application_secret = kwargs.get('application_secret', None)


class SynonymMap(msrest.serialization.Model):
"""Represents a synonym map definition.

Variables are only populated by the server, and will be ignored when sending a request.

All required parameters must be populated in order to send to Azure.

:param name: Required. The name of the synonym map.
:type name: str
:ivar format: Required. The format of the synonym map. Only the 'solr' format is currently
supported. Default value: "solr".
:vartype format: str
:param synonyms: Required. A series of synonym rules in the specified synonym map format. The
rules must be separated by newlines.
:type synonyms: str
:param encryption_key: A description of an encryption key that you create in Azure Key Vault.
This key is used to provide an additional level of encryption-at-rest for your data when you
want full assurance that no one, not even Microsoft, can decrypt your data in Azure Cognitive
Search. Once you have encrypted your data, it will always remain encrypted. Azure Cognitive
Search will ignore attempts to set this property to null. You can change this property as
needed if you want to rotate your encryption key; Your data will be unaffected. Encryption with
customer-managed keys is not available for free search services, and is only available for paid
services created on or after January 1, 2019.
:type encryption_key: ~azure.search.documents.models.SearchResourceEncryptionKey
:param e_tag: The ETag of the synonym map.
:type e_tag: str
"""

_validation = {
'name': {'required': True},
'format': {'required': True, 'constant': True},
'synonyms': {'required': True},
}

_attribute_map = {
'name': {'key': 'name', 'type': 'str'},
'format': {'key': 'format', 'type': 'str'},
'synonyms': {'key': 'synonyms', 'type': '[str]'},
'encryption_key': {'key': 'encryptionKey', 'type': 'SearchResourceEncryptionKey'},
'e_tag': {'key': '@odata\\.etag', 'type': 'str'},
}

format = "solr"

def __init__(
self,
**kwargs
):
super(SynonymMap, self).__init__(**kwargs)
self.name = kwargs['name']
self.synonyms = kwargs['synonyms']
self.encryption_key = kwargs.get('encryption_key', None)
self.e_tag = kwargs.get('e_tag', None)
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@
from azure.core.paging import ItemPaged

from ._generated import SearchServiceClient as _SearchServiceClient
from ._generated.models import SynonymMap
from ._generated.models import SynonymMap as _SynonymMap
from ._utils import (
delistize_flags_for_index,
listize_flags_for_index,
listize_synonyms,
pack_search_resource_encryption_key,
get_access_conditions,
normalize_endpoint,
)
Expand Down Expand Up @@ -275,7 +276,7 @@ def get_synonym_maps(self, **kwargs):
"""List the Synonym Maps in an Azure Search service.

:return: List of synonym maps
:rtype: list[dict]
:rtype: list[~azure.search.documents.indexes.models.SynonymMap]
:raises: ~azure.core.exceptions.HttpResponseError

.. admonition:: Example:
Expand All @@ -290,17 +291,17 @@ def get_synonym_maps(self, **kwargs):
"""
kwargs["headers"] = self._merge_client_headers(kwargs.get("headers"))
result = self._client.synonym_maps.list(**kwargs)
return [listize_synonyms(x) for x in result.as_dict()["synonym_maps"]]
return [listize_synonyms(x) for x in result.synonym_maps]

@distributed_trace
def get_synonym_map(self, name, **kwargs):
# type: (str, **Any) -> dict
# type: (str, **Any) -> SynonymMap
"""Retrieve a named Synonym Map in an Azure Search service

:param name: The name of the Synonym Map to get
:type name: str
:return: The retrieved Synonym Map
:rtype: dict
:rtype: :class:`~azure.search.documents.indexes.models.SynonymMap`
:raises: :class:`~azure.core.exceptions.ResourceNotFoundError`

.. admonition:: Example:
Expand All @@ -315,7 +316,7 @@ def get_synonym_map(self, name, **kwargs):
"""
kwargs["headers"] = self._merge_client_headers(kwargs.get("headers"))
result = self._client.synonym_maps.get(name, **kwargs)
return listize_synonyms(result.as_dict())
return listize_synonyms(result)

@distributed_trace
def delete_synonym_map(self, synonym_map, **kwargs):
Expand Down Expand Up @@ -356,15 +357,15 @@ def delete_synonym_map(self, synonym_map, **kwargs):

@distributed_trace
def create_synonym_map(self, name, synonyms, **kwargs):
# type: (str, Sequence[str], **Any) -> dict
# type: (str, Sequence[str], **Any) -> SynonymMap
"""Create a new Synonym Map in an Azure Search service

:param name: The name of the Synonym Map to create
:type name: str
:param synonyms: The list of synonyms in SOLR format
:type synonyms: List[str]
:return: The created Synonym Map
:rtype: dict
:rtype: ~azure.search.documents.indexes.models.SynonymMap

.. admonition:: Example:

Expand All @@ -378,13 +379,13 @@ def create_synonym_map(self, name, synonyms, **kwargs):
"""
kwargs["headers"] = self._merge_client_headers(kwargs.get("headers"))
solr_format_synonyms = "\n".join(synonyms)
synonym_map = SynonymMap(name=name, synonyms=solr_format_synonyms)
synonym_map = _SynonymMap(name=name, synonyms=solr_format_synonyms)
result = self._client.synonym_maps.create(synonym_map, **kwargs)
return listize_synonyms(result.as_dict())
return listize_synonyms(result)
xiangyan99 marked this conversation as resolved.
Show resolved Hide resolved

@distributed_trace
def create_or_update_synonym_map(self, synonym_map, synonyms=None, **kwargs):
# type: (Union[str, SynonymMap], Optional[Sequence[str]], **Any) -> dict
# type: (Union[str, SynonymMap], Optional[Sequence[str]], **Any) -> SynonymMap
"""Create a new Synonym Map in an Azure Search service, or update an
existing one.

Expand All @@ -395,7 +396,7 @@ def create_or_update_synonym_map(self, synonym_map, synonyms=None, **kwargs):
:keyword match_condition: The match condition to use upon the etag
:type match_condition: ~azure.core.MatchConditions
:return: The created or updated Synonym Map
:rtype: dict
:rtype: ~azure.search.documents.indexes.models.SynonymMap

"""
kwargs["headers"] = self._merge_client_headers(kwargs.get("headers"))
Expand All @@ -407,17 +408,18 @@ def create_or_update_synonym_map(self, synonym_map, synonyms=None, **kwargs):
name = synonym_map.name
if synonyms:
synonym_map.synonyms = "\n".join(synonyms)
synonym_map.encryption_key = pack_search_resource_encryption_key(synonym_map.encryption_key)
except AttributeError:
name = synonym_map
solr_format_synonyms = "\n".join(synonyms)
synonym_map = SynonymMap(name=name, synonyms=solr_format_synonyms)
synonym_map = _SynonymMap(name=name, synonyms=solr_format_synonyms)
result = self._client.synonym_maps.create_or_update(
synonym_map_name=name,
synonym_map=synonym_map,
error_map=error_map,
**kwargs
)
return listize_synonyms(result.as_dict())
return listize_synonyms(result)

@distributed_trace
def get_service_statistics(self, **kwargs):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@
class SearchIndexerClient(HeadersMixin):
"""A client to interact with Azure search service Indexers.

This class is not normally instantiated directly, instead use
`get_indexers_client()` from a `SearchServiceClient`

"""

_ODATA_ACCEPT = "application/json;odata.metadata=minimal" # type: str
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,19 @@
ResourceNotModifiedError,
)
from ._generated.models import (
AzureActiveDirectoryApplicationCredentials,
SearchResourceEncryptionKey as _SearchResourceEncryptionKey,
SynonymMap as _SynonymMap,
SearchIndex,
PatternAnalyzer as _PatternAnalyzer,
PatternTokenizer as _PatternTokenizer,
)
from ._models import PatternAnalyzer, PatternTokenizer
from ._models import (
PatternAnalyzer,
PatternTokenizer,
SynonymMap,
SearchResourceEncryptionKey,
)

if TYPE_CHECKING:
# pylint:disable=unused-import,ungrouped-imports
Expand Down Expand Up @@ -154,10 +162,40 @@ def listize_flags_for_index(index):


def listize_synonyms(synonym_map):
# type: (dict) -> dict
synonym_map["synonyms"] = synonym_map["synonyms"].split("\n")
return synonym_map
# type: (_SynonymMap) -> SynonymMap
return SynonymMap(
name=synonym_map.name,
synonyms=synonym_map.synonyms.split("\n"),
encryption_key=unpack_search_resource_encryption_key(synonym_map.encryption_key),
e_tag=synonym_map.e_tag
)

def pack_search_resource_encryption_key(search_resource_encryption_key):
# type: (SearchResourceEncryptionKey) -> _SearchResourceEncryptionKey
if not search_resource_encryption_key:
return None
access_credentials = AzureActiveDirectoryApplicationCredentials(
application_id=search_resource_encryption_key.application_id,
application_secret=search_resource_encryption_key.application_secret
)
return _SearchResourceEncryptionKey(
key_name=search_resource_encryption_key.key_name,
key_version=search_resource_encryption_key.key_version,
vault_uri=search_resource_encryption_key.vault_uri,
access_credentials=access_credentials
)

def unpack_search_resource_encryption_key(search_resource_encryption_key):
# type: (_SearchResourceEncryptionKey) -> SearchResourceEncryptionKey
if not search_resource_encryption_key:
return None
return SearchResourceEncryptionKey(
key_name=search_resource_encryption_key.key_name,
key_version=search_resource_encryption_key.key_version,
vault_uri=search_resource_encryption_key.vault_uri,
application_id=search_resource_encryption_key.access_credentials.application_id,
application_secret=search_resource_encryption_key.access_credentials.application_secret
)

def get_access_conditions(model, match_condition=MatchConditions.Unconditionally):
# type: (Any, MatchConditions) -> Tuple[Dict[int, Any], Dict[str, bool]]
Expand Down
Loading