def solrSearchResults(request=None, **keywords): """ perform a query using solr after translating the passed in parameters with portal catalog semantics """ search = queryUtility(ISearch) config = queryUtility(ISolrConnectionConfig) if request is None: # try to get a request instance, so that flares can be adapted to # ploneflares and urls can be converted into absolute ones etc; # however, in this case any arguments from the request are ignored request = getattr(getSite(), 'REQUEST', None) args = deepcopy(keywords) elif IHTTPRequest.providedBy(request): args = deepcopy(request.form) # ignore headers and other stuff args.update(keywords) # keywords take precedence else: assert isinstance(request, dict), request args = deepcopy(request) args.update(keywords) # keywords take precedence # if request is a dict, we need the real request in order to # be able to adapt to plone flares request = getattr(getSite(), 'REQUEST', args) if 'path' in args and 'navtree' in args['path']: raise FallBackException # we can't handle navtree queries yet use_solr = args.get('use_solr', False) # A special key to force Solr if not use_solr and config.required: required = set(config.required).intersection(args) if required: for key in required: if not args[key]: raise FallBackException else: raise FallBackException schema = search.getManager().getSchema() or {} params = cleanupQueryParameters(extractQueryParameters(args), schema) languageFilter(args) prepareData(args) mangleQuery(args, config, schema) query = search.buildQuery(**args) if query != {}: optimizeQueryParameters(query, params) __traceback_info__ = (query, params, args) response = search(query, **params) else: return SolrResponse() def wrap(flare): """ wrap a flare object with a helper class """ adapter = queryMultiAdapter((flare, request), IFlare) return adapter is not None and adapter or flare results = response.results() for idx, flare in enumerate(results): flare = wrap(flare) for missing in set(schema.stored).difference(flare): flare[missing] = MV results[idx] = wrap(flare) padResults(results, **params) # pad the batch return response
def buildQueryAndParameters(self, default=None, **args): """ helper to build a querystring for simple use-cases """ schema = self.getManager().getSchema() or {} params = subtractQueryParameters(args) params = cleanupQueryParameters(params, schema) config = self.getConfig() prepareData(args) mangleQuery(args, config, schema) logger.debug('building query for "%r", %r', default, args) schema = self.getManager().getSchema() or {} defaultSearchField = getattr(schema, 'defaultSearchField', None) args[None] = default query = {} for name, value in sorted(args.items()): field = schema.get(name or defaultSearchField, None) if field is None or not field.indexed: logger.info( 'dropping unknown search attribute "%s" ' ' (%r) for query: %r', name, value, args ) continue if isinstance(value, bool): value = str(value).lower() elif not value: # solr doesn't like empty fields (+foo:"") if not name: continue logger.info( 'empty search term form "%s:%s", aborting buildQuery' % ( name, value ) ) return {}, params elif field.class_ == 'solr.BoolField': if not isinstance(value, (tuple, list)): value = [value] falses = '0', 'False', MV true = lambda v: bool(v) and v not in falses value = set(map(true, value)) if not len(value) == 1: assert len(value) == 2 # just to make sure continue # skip when "true or false" value = str(value.pop()).lower() elif isinstance(value, (tuple, list)): # list items should be treated as literals, but # nevertheless only get quoted when necessary value = '(%s)' % ' OR '.join(map(quote_iterable_item, value)) elif isinstance(value, set): # sets are taken literally if len(value) == 1: query[name] = ''.join(value) else: query[name] = '(%s)' % ' OR '.join(value) continue elif isinstance(value, basestring): if field.class_ == 'solr.TextField': if isWildCard(value): value = prepare_wildcard(value) value = quote(value, textfield=True) # if we have an intra-word hyphen, we need quotes if '\\-' in value or '\\+' in value: if value[0] != '"': value = '"%s"' % value else: value = quote(value) if not value: # don't search for empty strings, even quoted continue else: logger.info( 'skipping unsupported value "%r" (%s)', value, name ) continue if name is None: if value and value[0] not in '+-': value = '+%s' % value else: value = '+%s:%s' % (name, value) query[name] = value logger.debug('built query "%s"', query) if query: optimizeQueryParameters(query, params) return query, params