Example #1
0
def general_search(query):
    """ Queries of full equations should not call this, but we won't catch
        pieces of an equation without '=', '+', lt, or gt, so we have to 
        account for those. An icontains filter ought to cover it. """
    predicates = [Q(term__icontains=s) for s in predicate_string_set(query)]
    term_results = SearchTerm.objects.filter(reduce(operator.or_, predicates))\
       .prefetch_related(*chain(__VAR_PREFETCH, __EQ_PREFETCH, __UNIT_PREFETCH))
    if not term_results.count():
        return None
    dataQ = SmartPQ()
    for t in term_results:
        for obj in chain(t.variable_set.all(), t.equation_set.all(), t.unit_set.all()):
            investigate_object(obj, query, dataQ)
    return dataQ.ordered_list()
Example #2
0
def equation_exclusive_search(query):
    """ Since there are math characters in the query, we don't have to waste
        time querying other models. We can just check equations. """
    # our equations should not have spaces or stars. Underscores and parens may
    # occur, but there should be a SearchTerm in the database with parens and
    # underscores stripped. For edge cases, we include those queries anyway
    init_predicate_strings = predicate_string_set(query)
    eq_operator_split = lambda q: re.split(r'[=+\-*/^<>]+', q)
    predicate_strings = copy(init_predicate_strings)
    for q_string in init_predicate_strings:
        for component in eq_operator_split(q_string):
            predicate_strings.add(component)
    predicates = [Q(term__icontains=s) for s in predicate_strings]
    term_results = SearchTerm.objects.filter(reduce(operator.or_, predicates))\
                                             .prefetch_related(*__EQ_PREFETCH)
    if not term_results.count():
        # using .count() so that we don't evaluate the queryset if not needed
        return None
    dataQ = SmartPQ() # custom priority queue for O(1) lookup!
    any_in_set = lambda fcn, set_: any(fcn(q) for q in set_)
    for t in term_results:
        for eq in t.equation_set.all():
            to_add = eq
            if eq.is_definition():
                to_add = eq.defined_var
            if dataQ.has_value(to_add):
                continue
            eqname = eq.quick_name
            l_eqname = eqname.lower()
            # don't bother checking full_names since we know we have math text.
            # full_names do not contain math.
            # PRIORITY 0: quick name exact match for any in basic string set
            if any_in_set(lambda q: q == eqname, init_predicate_strings):
                dataQ.put((0, to_add))
            # PRIORITY 1: same as 0, but case insensitive
            elif any_in_set(lambda q: q.lower() == l_eqname, init_predicate_strings):
                dataQ.put((1, to_add))
            # PRIORITY 2: alternative name case insensitive match
            elif any(any_in_set(lambda q: q.lower() == alt.term.lower(),
                     init_predicate_strings) for alt in eq.search_terms.all() if 
                     alt.term != eqname):
                dataQ.put((2, to_add))
            # expand modified query set to components of operator splits
            # PRIORITY 3: substrings of quick_names
            elif any_in_set(lambda q: q.lower() in l_eqname, predicate_strings):
                dataQ.put((3, to_add))
            # PRIORITY 4: substrings of altnames
            elif any(any_in_set(lambda q: q.lower() in alt.term.lower(), 
                     predicate_strings) for alt in eq.search_terms.all() if 
                     alt.term != eqname):
                dataQ.put((4, to_add))
            # PRIORITY 5: anything else caught in our database query
            else:
                dataQ.put((5, to_add)) 
    return dataQ.ordered_list()