|
21 | 21 |
|
22 | 22 | from requests.exceptions import HTTPError |
23 | 23 |
|
24 | | -from ._2to3 import url_quote_plus |
| 24 | +from ._2to3 import url_quote_plus, iteritems_ |
| 25 | +from ._common_util import ( |
| 26 | + JSON_INDEX_TYPE, |
| 27 | + SEARCH_INDEX_ARGS, |
| 28 | + SPECIAL_INDEX_TYPE, |
| 29 | + TEXT_INDEX_TYPE, |
| 30 | + python_to_couch |
| 31 | +) |
25 | 32 | from .document import Document |
26 | 33 | from .design_document import DesignDocument |
27 | 34 | from .view import View |
28 | 35 | from .index import Index, TextIndex, SpecialIndex |
29 | | -from ._common_util import JSON_INDEX_TYPE |
30 | | -from ._common_util import TEXT_INDEX_TYPE |
31 | | -from ._common_util import SPECIAL_INDEX_TYPE |
32 | | -from ._common_util import python_to_couch |
33 | 36 | from .query import Query |
34 | 37 | from .error import CloudantException, CloudantArgumentError |
35 | 38 | from .result import Result, QueryResult |
@@ -1098,3 +1101,128 @@ def get_query_result(self, selector, fields=None, raw_result=False, |
1098 | 1101 | return QueryResult(query, **kwargs) |
1099 | 1102 | else: |
1100 | 1103 | return query.result |
| 1104 | + |
| 1105 | + def get_search_result(self, ddoc_id, index_name, **query_params): |
| 1106 | + """ |
| 1107 | + Retrieves the raw JSON content from the remote database based on the |
| 1108 | + search index on the server, using the query_params provided as query |
| 1109 | + parameters. A ``query`` parameter containing the Lucene query |
| 1110 | + syntax is mandatory. |
| 1111 | +
|
| 1112 | + Example for search queries: |
| 1113 | +
|
| 1114 | + .. code-block:: python |
| 1115 | +
|
| 1116 | + # Assuming that 'searchindex001' exists as part of the |
| 1117 | + # 'ddoc001' design document in the remote database... |
| 1118 | + # Retrieve documents where the Lucene field name is 'name' and |
| 1119 | + # the value is 'julia*' |
| 1120 | + resp = db.get_search_result('ddoc001', 'searchindex001', |
| 1121 | + query='name:julia*', |
| 1122 | + include_docs=True) |
| 1123 | + for row in resp['rows']: |
| 1124 | + # Process search index data (in JSON format). |
| 1125 | +
|
| 1126 | + Example if the search query requires grouping by using |
| 1127 | + the ``group_field`` parameter: |
| 1128 | +
|
| 1129 | + .. code-block:: python |
| 1130 | +
|
| 1131 | + # Assuming that 'searchindex001' exists as part of the |
| 1132 | + # 'ddoc001' design document in the remote database... |
| 1133 | + # Retrieve JSON response content, limiting response to 10 documents |
| 1134 | + resp = db.get_search_result('ddoc001', 'searchindex001', |
| 1135 | + query='name:julia*', |
| 1136 | + group_field='name', |
| 1137 | + limit=10) |
| 1138 | + for group in resp['groups']: |
| 1139 | + for row in group['rows']: |
| 1140 | + # Process search index data (in JSON format). |
| 1141 | +
|
| 1142 | + :param str ddoc_id: Design document id used to get the search result. |
| 1143 | + :param str index_name: Name used in part to identify the index. |
| 1144 | + :param str bookmark: Optional string that enables you to specify which |
| 1145 | + page of results you require. Only valid for queries that do not |
| 1146 | + specify the ``group_field`` query parameter. |
| 1147 | + :param list counts: Optional JSON array of field names for which |
| 1148 | + counts should be produced. The response will contain counts for each |
| 1149 | + unique value of this field name among the documents matching the |
| 1150 | + search query. |
| 1151 | + Requires the index to have faceting enabled. |
| 1152 | + :param list drilldown: Optional list of fields that each define a |
| 1153 | + pair of a field name and a value. This field can be used several |
| 1154 | + times. The search will only match documents that have the given |
| 1155 | + value in the field name. It differs from using |
| 1156 | + ``query=fieldname:value` only in that the values are not analyzed. |
| 1157 | + :param str group_field: Optional string field by which to group |
| 1158 | + search matches. Fields containing other data |
| 1159 | + (numbers, objects, arrays) can not be used. |
| 1160 | + :param int group_limit: Optional number with the maximum group count. |
| 1161 | + This field can only be used if ``group_field`` query parameter |
| 1162 | + is specified. |
| 1163 | + :param group_sort: Optional JSON field that defines the order of the |
| 1164 | + groups in a search using ``group_field``. The default sort order |
| 1165 | + is relevance. This field can have the same values as the sort field, |
| 1166 | + so single fields as well as arrays of fields are supported. |
| 1167 | + :param int limit: Optional number to limit the maximum count of the |
| 1168 | + returned documents. In case of a grouped search, this parameter |
| 1169 | + limits the number of documents per group. |
| 1170 | + :param query: A Lucene query in the form of ``name:value``. |
| 1171 | + If name is omitted, the special value ``default`` is used. |
| 1172 | + :param ranges: Optional JSON facet syntax that reuses the standard |
| 1173 | + Lucene syntax to return counts of results which fit into each |
| 1174 | + specified category. Inclusive range queries are denoted by brackets. |
| 1175 | + Exclusive range queries are denoted by curly brackets. |
| 1176 | + For example ``ranges={"price":{"cheap":"[0 TO 100]"}}`` has an |
| 1177 | + inclusive range of 0 to 100. |
| 1178 | + Requires the index to have faceting enabled. |
| 1179 | + :param sort: Optional JSON string of the form ``fieldname<type>`` for |
| 1180 | + ascending or ``-fieldname<type>`` for descending sort order. |
| 1181 | + Fieldname is the name of a string or number field and type is either |
| 1182 | + number or string or a JSON array of such strings. The type part is |
| 1183 | + optional and defaults to number. |
| 1184 | + :param str stale: Optional string to allow the results from a stale |
| 1185 | + index to be used. This makes the request return immediately, even |
| 1186 | + if the index has not been completely built yet. |
| 1187 | + :param list highlight_fields: Optional list of fields which should be |
| 1188 | + highlighted. |
| 1189 | + :param str highlight_pre_tag: Optional string inserted before the |
| 1190 | + highlighted word in the highlights output. Defaults to ``<em>``. |
| 1191 | + :param str highlight_post_tag: Optional string inserted after the |
| 1192 | + highlighted word in the highlights output. Defaults to ``</em>``. |
| 1193 | + :param int highlight_number: Optional number of fragments returned in |
| 1194 | + highlights. If the search term occurs less often than the number of |
| 1195 | + fragments specified, longer fragments are returned. Default is 1. |
| 1196 | + :param int highlight_size: Optional number of characters in each |
| 1197 | + fragment for highlights. Defaults to 100 characters. |
| 1198 | + :param list include_fields: Optional list of field names to include in |
| 1199 | + search results. Any fields included must have been indexed with the |
| 1200 | + ``store:true`` option. |
| 1201 | +
|
| 1202 | + :returns: Search query result data in JSON format |
| 1203 | + """ |
| 1204 | + if not query_params.get('query'): |
| 1205 | + raise CloudantArgumentError( |
| 1206 | + 'No query parameter found. Please add a query parameter ' |
| 1207 | + 'containing Lucene syntax and retry.') |
| 1208 | + |
| 1209 | + # Validate query arguments and values |
| 1210 | + for key, val in iteritems_(query_params): |
| 1211 | + if key not in list(SEARCH_INDEX_ARGS.keys()): |
| 1212 | + msg = 'Invalid argument: {0}'.format(key) |
| 1213 | + raise CloudantArgumentError(msg) |
| 1214 | + if not isinstance(val, SEARCH_INDEX_ARGS[key]): |
| 1215 | + msg = ( |
| 1216 | + 'Argument {0} is not an instance of expected type: {1}' |
| 1217 | + ).format(key, SEARCH_INDEX_ARGS[key]) |
| 1218 | + raise CloudantArgumentError(msg) |
| 1219 | + # Execute query search |
| 1220 | + headers = {'Content-Type': 'application/json'} |
| 1221 | + ddoc = DesignDocument(self, ddoc_id) |
| 1222 | + resp = self.r_session.post( |
| 1223 | + '/'.join([ddoc.document_url, '_search', index_name]), |
| 1224 | + headers=headers, |
| 1225 | + data=json.dumps(query_params, cls=self.client.encoder) |
| 1226 | + ) |
| 1227 | + resp.raise_for_status() |
| 1228 | + return resp.json() |
0 commit comments