OLD | NEW |
(Empty) | |
| 1 # Copyright (c) 2012 Mitch Garnaat http://garnaat.org/ |
| 2 # Copyright (c) 2012 Amazon.com, Inc. or its affiliates. |
| 3 # All Rights Reserved |
| 4 # |
| 5 # Permission is hereby granted, free of charge, to any person obtaining a |
| 6 # copy of this software and associated documentation files (the |
| 7 # "Software"), to deal in the Software without restriction, including |
| 8 # without limitation the rights to use, copy, modify, merge, publish, dis- |
| 9 # tribute, sublicense, and/or sell copies of the Software, and to permit |
| 10 # persons to whom the Software is furnished to do so, subject to the fol- |
| 11 # lowing conditions: |
| 12 # |
| 13 # The above copyright notice and this permission notice shall be included |
| 14 # in all copies or substantial portions of the Software. |
| 15 # |
| 16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| 17 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- |
| 18 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT |
| 19 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| 20 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 21 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
| 22 # IN THE SOFTWARE. |
| 23 # |
| 24 |
| 25 import boto |
| 26 from boto.compat import json |
| 27 from .optionstatus import OptionStatus |
| 28 from .optionstatus import IndexFieldStatus |
| 29 from .optionstatus import ServicePoliciesStatus |
| 30 from .optionstatus import RankExpressionStatus |
| 31 from .document import DocumentServiceConnection |
| 32 from .search import SearchConnection |
| 33 |
| 34 def handle_bool(value): |
| 35 if value in [True, 'true', 'True', 'TRUE', 1]: |
| 36 return True |
| 37 return False |
| 38 |
| 39 |
| 40 class Domain(object): |
| 41 """ |
| 42 A Cloudsearch domain. |
| 43 |
| 44 :ivar name: The name of the domain. |
| 45 |
| 46 :ivar id: The internally generated unique identifier for the domain. |
| 47 |
| 48 :ivar created: A boolean which is True if the domain is |
| 49 created. It can take several minutes to initialize a domain |
| 50 when CreateDomain is called. Newly created search domains are |
| 51 returned with a False value for Created until domain creation |
| 52 is complete |
| 53 |
| 54 :ivar deleted: A boolean which is True if the search domain has |
| 55 been deleted. The system must clean up resources dedicated to |
| 56 the search domain when delete is called. Newly deleted |
| 57 search domains are returned from list_domains with a True |
| 58 value for deleted for several minutes until resource cleanup |
| 59 is complete. |
| 60 |
| 61 :ivar processing: True if processing is being done to activate the |
| 62 current domain configuration. |
| 63 |
| 64 :ivar num_searchable_docs: The number of documents that have been |
| 65 submittted to the domain and indexed. |
| 66 |
| 67 :ivar requires_index_document: True if index_documents needs to be |
| 68 called to activate the current domain configuration. |
| 69 |
| 70 :ivar search_instance_count: The number of search instances that are |
| 71 available to process search requests. |
| 72 |
| 73 :ivar search_instance_type: The instance type that is being used to |
| 74 process search requests. |
| 75 |
| 76 :ivar search_partition_count: The number of partitions across which |
| 77 the search index is spread. |
| 78 """ |
| 79 |
| 80 def __init__(self, layer1, data): |
| 81 self.layer1 = layer1 |
| 82 self.update_from_data(data) |
| 83 |
| 84 def update_from_data(self, data): |
| 85 self.created = data['created'] |
| 86 self.deleted = data['deleted'] |
| 87 self.processing = data['processing'] |
| 88 self.requires_index_documents = data['requires_index_documents'] |
| 89 self.domain_id = data['domain_id'] |
| 90 self.domain_name = data['domain_name'] |
| 91 self.num_searchable_docs = data['num_searchable_docs'] |
| 92 self.search_instance_count = data['search_instance_count'] |
| 93 self.search_instance_type = data.get('search_instance_type', None) |
| 94 self.search_partition_count = data['search_partition_count'] |
| 95 self._doc_service = data['doc_service'] |
| 96 self._search_service = data['search_service'] |
| 97 |
| 98 @property |
| 99 def doc_service_arn(self): |
| 100 return self._doc_service['arn'] |
| 101 |
| 102 @property |
| 103 def doc_service_endpoint(self): |
| 104 return self._doc_service['endpoint'] |
| 105 |
| 106 @property |
| 107 def search_service_arn(self): |
| 108 return self._search_service['arn'] |
| 109 |
| 110 @property |
| 111 def search_service_endpoint(self): |
| 112 return self._search_service['endpoint'] |
| 113 |
| 114 @property |
| 115 def created(self): |
| 116 return self._created |
| 117 |
| 118 @created.setter |
| 119 def created(self, value): |
| 120 self._created = handle_bool(value) |
| 121 |
| 122 @property |
| 123 def deleted(self): |
| 124 return self._deleted |
| 125 |
| 126 @deleted.setter |
| 127 def deleted(self, value): |
| 128 self._deleted = handle_bool(value) |
| 129 |
| 130 @property |
| 131 def processing(self): |
| 132 return self._processing |
| 133 |
| 134 @processing.setter |
| 135 def processing(self, value): |
| 136 self._processing = handle_bool(value) |
| 137 |
| 138 @property |
| 139 def requires_index_documents(self): |
| 140 return self._requires_index_documents |
| 141 |
| 142 @requires_index_documents.setter |
| 143 def requires_index_documents(self, value): |
| 144 self._requires_index_documents = handle_bool(value) |
| 145 |
| 146 @property |
| 147 def search_partition_count(self): |
| 148 return self._search_partition_count |
| 149 |
| 150 @search_partition_count.setter |
| 151 def search_partition_count(self, value): |
| 152 self._search_partition_count = int(value) |
| 153 |
| 154 @property |
| 155 def search_instance_count(self): |
| 156 return self._search_instance_count |
| 157 |
| 158 @search_instance_count.setter |
| 159 def search_instance_count(self, value): |
| 160 self._search_instance_count = int(value) |
| 161 |
| 162 @property |
| 163 def num_searchable_docs(self): |
| 164 return self._num_searchable_docs |
| 165 |
| 166 @num_searchable_docs.setter |
| 167 def num_searchable_docs(self, value): |
| 168 self._num_searchable_docs = int(value) |
| 169 |
| 170 @property |
| 171 def name(self): |
| 172 return self.domain_name |
| 173 |
| 174 @property |
| 175 def id(self): |
| 176 return self.domain_id |
| 177 |
| 178 def delete(self): |
| 179 """ |
| 180 Delete this domain and all index data associated with it. |
| 181 """ |
| 182 return self.layer1.delete_domain(self.name) |
| 183 |
| 184 def get_stemming(self): |
| 185 """ |
| 186 Return a :class:`boto.cloudsearch.option.OptionStatus` object |
| 187 representing the currently defined stemming options for |
| 188 the domain. |
| 189 """ |
| 190 return OptionStatus(self, None, |
| 191 self.layer1.describe_stemming_options, |
| 192 self.layer1.update_stemming_options) |
| 193 |
| 194 def get_stopwords(self): |
| 195 """ |
| 196 Return a :class:`boto.cloudsearch.option.OptionStatus` object |
| 197 representing the currently defined stopword options for |
| 198 the domain. |
| 199 """ |
| 200 return OptionStatus(self, None, |
| 201 self.layer1.describe_stopword_options, |
| 202 self.layer1.update_stopword_options) |
| 203 |
| 204 def get_synonyms(self): |
| 205 """ |
| 206 Return a :class:`boto.cloudsearch.option.OptionStatus` object |
| 207 representing the currently defined synonym options for |
| 208 the domain. |
| 209 """ |
| 210 return OptionStatus(self, None, |
| 211 self.layer1.describe_synonym_options, |
| 212 self.layer1.update_synonym_options) |
| 213 |
| 214 def get_access_policies(self): |
| 215 """ |
| 216 Return a :class:`boto.cloudsearch.option.OptionStatus` object |
| 217 representing the currently defined access policies for |
| 218 the domain. |
| 219 """ |
| 220 return ServicePoliciesStatus(self, None, |
| 221 self.layer1.describe_service_access_policie
s, |
| 222 self.layer1.update_service_access_policies) |
| 223 |
| 224 def index_documents(self): |
| 225 """ |
| 226 Tells the search domain to start indexing its documents using |
| 227 the latest text processing options and IndexFields. This |
| 228 operation must be invoked to make options whose OptionStatus |
| 229 has OptioState of RequiresIndexDocuments visible in search |
| 230 results. |
| 231 """ |
| 232 self.layer1.index_documents(self.name) |
| 233 |
| 234 def get_index_fields(self, field_names=None): |
| 235 """ |
| 236 Return a list of index fields defined for this domain. |
| 237 """ |
| 238 data = self.layer1.describe_index_fields(self.name, field_names) |
| 239 return [IndexFieldStatus(self, d) for d in data] |
| 240 |
| 241 def create_index_field(self, field_name, field_type, |
| 242 default='', facet=False, result=False, searchable=False, |
| 243 source_attributes=[]): |
| 244 """ |
| 245 Defines an ``IndexField``, either replacing an existing |
| 246 definition or creating a new one. |
| 247 |
| 248 :type field_name: string |
| 249 :param field_name: The name of a field in the search index. |
| 250 |
| 251 :type field_type: string |
| 252 :param field_type: The type of field. Valid values are |
| 253 uint | literal | text |
| 254 |
| 255 :type default: string or int |
| 256 :param default: The default value for the field. If the |
| 257 field is of type ``uint`` this should be an integer value. |
| 258 Otherwise, it's a string. |
| 259 |
| 260 :type facet: bool |
| 261 :param facet: A boolean to indicate whether facets |
| 262 are enabled for this field or not. Does not apply to |
| 263 fields of type ``uint``. |
| 264 |
| 265 :type results: bool |
| 266 :param results: A boolean to indicate whether values |
| 267 of this field can be returned in search results or |
| 268 used in ranking. Does not apply to fields of type ``uint``. |
| 269 |
| 270 :type searchable: bool |
| 271 :param searchable: A boolean to indicate whether search |
| 272 is enabled for this field or not. Applies only to fields |
| 273 of type ``literal``. |
| 274 |
| 275 :type source_attributes: list of dicts |
| 276 :param source_attributes: An optional list of dicts that |
| 277 provide information about attributes for this index field. |
| 278 A maximum of 20 source attributes can be configured for |
| 279 each index field. |
| 280 |
| 281 Each item in the list is a dict with the following keys: |
| 282 |
| 283 * data_copy - The value is a dict with the following keys: |
| 284 * default - Optional default value if the source attribute |
| 285 is not specified in a document. |
| 286 * name - The name of the document source field to add |
| 287 to this ``IndexField``. |
| 288 * data_function - Identifies the transformation to apply |
| 289 when copying data from a source attribute. |
| 290 * data_map - The value is a dict with the following keys: |
| 291 * cases - A dict that translates source field values |
| 292 to custom values. |
| 293 * default - An optional default value to use if the |
| 294 source attribute is not specified in a document. |
| 295 * name - the name of the document source field to add |
| 296 to this ``IndexField`` |
| 297 * data_trim_title - Trims common title words from a source |
| 298 document attribute when populating an ``IndexField``. |
| 299 This can be used to create an ``IndexField`` you can |
| 300 use for sorting. The value is a dict with the following |
| 301 fields: |
| 302 * default - An optional default value. |
| 303 * language - an IETF RFC 4646 language code. |
| 304 * separator - The separator that follows the text to trim. |
| 305 * name - The name of the document source field to add. |
| 306 |
| 307 :raises: BaseException, InternalException, LimitExceededException, |
| 308 InvalidTypeException, ResourceNotFoundException |
| 309 """ |
| 310 data = self.layer1.define_index_field(self.name, field_name, |
| 311 field_type, default=default, |
| 312 facet=facet, result=result, |
| 313 searchable=searchable, |
| 314 source_attributes=source_attribute
s) |
| 315 return IndexFieldStatus(self, data, |
| 316 self.layer1.describe_index_fields) |
| 317 |
| 318 def get_rank_expressions(self, rank_names=None): |
| 319 """ |
| 320 Return a list of rank expressions defined for this domain. |
| 321 """ |
| 322 fn = self.layer1.describe_rank_expressions |
| 323 data = fn(self.name, rank_names) |
| 324 return [RankExpressionStatus(self, d, fn) for d in data] |
| 325 |
| 326 def create_rank_expression(self, name, expression): |
| 327 """ |
| 328 Create a new rank expression. |
| 329 |
| 330 :type rank_name: string |
| 331 :param rank_name: The name of an expression computed for ranking |
| 332 while processing a search request. |
| 333 |
| 334 :type rank_expression: string |
| 335 :param rank_expression: The expression to evaluate for ranking |
| 336 or thresholding while processing a search request. The |
| 337 RankExpression syntax is based on JavaScript expressions |
| 338 and supports: |
| 339 |
| 340 * Integer, floating point, hex and octal literals |
| 341 * Shortcut evaluation of logical operators such that an |
| 342 expression a || b evaluates to the value a if a is |
| 343 true without evaluting b at all |
| 344 * JavaScript order of precedence for operators |
| 345 * Arithmetic operators: + - * / % |
| 346 * Boolean operators (including the ternary operator) |
| 347 * Bitwise operators |
| 348 * Comparison operators |
| 349 * Common mathematic functions: abs ceil erf exp floor |
| 350 lgamma ln log2 log10 max min sqrt pow |
| 351 * Trigonometric library functions: acosh acos asinh asin |
| 352 atanh atan cosh cos sinh sin tanh tan |
| 353 * Random generation of a number between 0 and 1: rand |
| 354 * Current time in epoch: time |
| 355 * The min max functions that operate on a variable argument list |
| 356 |
| 357 Intermediate results are calculated as double precision |
| 358 floating point values. The final return value of a |
| 359 RankExpression is automatically converted from floating |
| 360 point to a 32-bit unsigned integer by rounding to the |
| 361 nearest integer, with a natural floor of 0 and a ceiling |
| 362 of max(uint32_t), 4294967295. Mathematical errors such as |
| 363 dividing by 0 will fail during evaluation and return a |
| 364 value of 0. |
| 365 |
| 366 The source data for a RankExpression can be the name of an |
| 367 IndexField of type uint, another RankExpression or the |
| 368 reserved name text_relevance. The text_relevance source is |
| 369 defined to return an integer from 0 to 1000 (inclusive) to |
| 370 indicate how relevant a document is to the search request, |
| 371 taking into account repetition of search terms in the |
| 372 document and proximity of search terms to each other in |
| 373 each matching IndexField in the document. |
| 374 |
| 375 For more information about using rank expressions to |
| 376 customize ranking, see the Amazon CloudSearch Developer |
| 377 Guide. |
| 378 |
| 379 :raises: BaseException, InternalException, LimitExceededException, |
| 380 InvalidTypeException, ResourceNotFoundException |
| 381 """ |
| 382 data = self.layer1.define_rank_expression(self.name, name, expression) |
| 383 return RankExpressionStatus(self, data, |
| 384 self.layer1.describe_rank_expressions) |
| 385 |
| 386 def get_document_service(self): |
| 387 return DocumentServiceConnection(domain=self) |
| 388 |
| 389 def get_search_service(self): |
| 390 return SearchConnection(domain=self) |
| 391 |
| 392 def __repr__(self): |
| 393 return '<Domain: %s>' % self.domain_name |
| 394 |
OLD | NEW |