Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django haystack, priority for some fields in search

I have a model like this:

class MyModel(models.Model):
    desc1 = models.TextField(blank=True, default="")
    desc2 = models.TextField(blank=True, default="")

I want to search string on fields of this model. Assume these instances of MyModel:

1: desc1="ABc?", desc2="asdasd you"
2: desc1="Hello, How are you?", desc2="Thank you!"
3: desc1="ABc?", desc2="ajdf"

when I search "you", it should show me, first and second instances. finally I need to show the results which have "you" in desc1 higher than others. for example, in this sample, second one should be higher than first one.

I have used, haystack for search and created a template for this. but I couldn't solve the priority problem.

like image 245
Pooria Kaviani Avatar asked May 10 '12 16:05

Pooria Kaviani


2 Answers

When you say 'priority' you really mean 'sort', in the lingo of searching.

Django Haystack can sort by field matches, but it can sort by 'score', where it uses an algorithm to determine the sort order. You can influence the weighting of the score with 'Boost'ing it -- see http://django-haystack.readthedocs.org/en/latest/boost.html

Also, you should consider adding extra fields in your search_indexes.py that will be just for weighting. You don't need to have a one-to-one mapping between the Django model fields and the index. Something like

class MyModelIndex(QueuedSearchIndex):
    desc1 = indexes.CharField()
    desc2 = indexes.CharField()
    otherWeightedField = indexes.CharField()

    def prepare_otherWeightedField(self,obj)
        # fill the extra field with extra stuff to help you sort, based on processing values from other fields
like image 117
Mark Chackerian Avatar answered Oct 05 '22 23:10

Mark Chackerian


I use this approach.

from types import ListType
from haystack import indexes


class DocumentField(indexes.SearchField):
    """An index field that combines and weights other fields because Haystack
    does not provide for weighted searching. This field makes use of other
    existing field classes for DRY."""

    def __init__(self, *args, **kwargs):
        self.fields = kwargs.pop("fields", None)
        super(DocumentField, self).__init__(*args, **kwargs)
        self.document = True
        self.use_template = False

    def prepare(self, obj):
        values = []

        for field_instance in self.fields.values():
            v = field_instance.prepare(obj)
            if not v:
                continue
            if not isinstance(v, ListType):
                v = [v]
            # Apply boost
            v = v * int(field_instance.boost * 10)
            values.extend(v)

        return "\n".join(values)


class MyModelIndex(indexes.SearchIndex, indexes.Indexable):
    text = DocumentField(fields=dict(
        desc1 = indexes.CharField(model_attr="desc1", boost=1.0),
        desc2 = indexes.CharField(model_attr="desc2", boost=0.7)
    ))

    def get_model(self):
        return MyModel
like image 27
hedleyroos Avatar answered Oct 06 '22 00:10

hedleyroos