+ @staticmethod
+ def enum_to_array(enum):
+ """
+ Converts a lucene TermEnum to array of Terms, suitable for
+ addition to queries
+ """
+ terms = []
+
+ while True:
+ t = enum.term()
+ if t:
+ terms.append(t)
+ if not enum.next(): break
+
+ if terms:
+ return JArray('object')(terms, Term)
+
+ def search_tags(self, query, filt=None, max_results=40, pdcounter=False):
+ """
+ Search for Tag objects using query.
+ """
+ if not pdcounter:
+ filters = self.chain_filters([filt, self.term_filter(Term('is_pdcounter', 'true'), inverse=True)])
+ tops = self.searcher.search(query, filt, max_results)
+
+ tags = []
+ for found in tops.scoreDocs:
+ doc = self.searcher.doc(found.doc)
+ is_pdcounter = doc.get('is_pdcounter')
+ category = doc.get('tag_category')
+ try:
+ if is_pdcounter == 'true':
+ if category == 'pd_author':
+ tag = PDCounterAuthor.objects.get(id=doc.get('tag_id'))
+ elif category == 'pd_book':
+ tag = PDCounterBook.objects.get(id=doc.get('tag_id'))
+ tag.category = 'pd_book' # make it look more lik a tag.
+ else:
+ print "Warning. cannot get pdcounter tag_id=%d from db; cat=%s" % (int(doc.get('tag_id')), category)
+ else:
+ tag = catalogue.models.Tag.objects.get(id=doc.get("tag_id"))
+ # don't add the pdcounter tag if same tag already exists
+ if not (is_pdcounter and filter(lambda t: tag.slug == t.slug, tags)):
+ tags.append(tag)
+ except catalogue.models.Tag.DoesNotExist: pass
+ except PDCounterAuthor.DoesNotExist: pass
+ except PDCounterBook.DoesNotExist: pass
+
+ log.debug('search_tags: %s' % tags)
+
+ return tags
+
+ def search_books(self, query, filt=None, max_results=10):
+ """
+ Searches for Book objects using query
+ """
+ bks = []
+ tops = self.searcher.search(query, filt, max_results)
+ for found in tops.scoreDocs:
+ doc = self.searcher.doc(found.doc)
+ try:
+ bks.append(catalogue.models.Book.objects.get(id=doc.get("book_id")))
+ except catalogue.models.Book.DoesNotExist: pass
+ return bks
+
+ def make_prefix_phrase(self, toks, field):
+ q = MultiPhraseQuery()
+ for i in range(len(toks)):
+ t = Term(field, toks[i])
+ if i == len(toks) - 1:
+ pterms = Search.enum_to_array(PrefixTermEnum(self.searcher.getIndexReader(), t))
+ if pterms:
+ q.add(pterms)
+ else:
+ q.add(t)
+ else:
+ q.add(t)
+ return q
+
+ @staticmethod
+ def term_filter(term, inverse=False):
+ only_term = TermsFilter()
+ only_term.addTerm(term)
+
+ if inverse:
+ neg = BooleanFilter()
+ neg.add(FilterClause(only_term, BooleanClause.Occur.MUST_NOT))
+ only_term = neg
+
+ return only_term
+
+ def hint_tags(self, string, max_results=50, pdcounter=True, prefix=True, fuzzy=False):
+ """
+ Return auto-complete hints for tags
+ using prefix search.
+ """
+ toks = self.get_tokens(string, field='SIMPLE')
+ top = BooleanQuery()
+
+ for field in ['tag_name', 'tag_name_pl']:
+ if prefix:
+ q = self.make_prefix_phrase(toks, field)
+ else:
+ q = self.make_term_query(toks, field, fuzzy=fuzzy)
+ top.add(BooleanClause(q, BooleanClause.Occur.SHOULD))
+
+ no_book_cat = self.term_filter(Term("tag_category", "book"), inverse=True)
+
+ return self.search_tags(top, no_book_cat, max_results=max_results, pdcounter=pdcounter)
+
+ def hint_books(self, string, max_results=50, prefix=True, fuzzy=False):
+ """
+ Returns auto-complete hints for book titles
+ Because we do not index 'pseudo' title-tags.
+ Prefix search.
+ """
+ toks = self.get_tokens(string, field='SIMPLE')
+
+ if prefix:
+ q = self.make_prefix_phrase(toks, 'title')
+ else:
+ q = self.make_term_query(toks, 'title', fuzzy=fuzzy)
+
+ return self.search_books(q, self.term_filter(Term("is_book", "true")), max_results=max_results)
+
+ @staticmethod
+ def chain_filters(filters, op=ChainedFilter.AND):
+ """
+ Chains a filter list together
+ """
+ filters = filter(lambda x: x is not None, filters)
+ if not filters or filters is []:
+ return None
+ chf = ChainedFilter(JArray('object')(filters, Filter), op)
+ return chf
+
+ def filtered_categories(self, tags):
+ """
+ Return a list of tag categories, present in tags list.
+ """
+ cats = {}
+ for t in tags:
+ cats[t.category] = True
+ return cats.keys()