Django haystack, priority for some fields in search
Asked Answered
G

2

6

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.

Guadalupeguadeloupe answered 10/5, 2012 at 16:59 Comment(0)
V
3

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
Vaucluse answered 26/7, 2012 at 18:23 Comment(2)
The "boosting" API appears very unstable. The doc you link to shows a completely different approach...which doesn't even work with the current code...Tavern
Just to be clear, this is an example that was written for Haystack 1.2Vaucluse
T
3

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
Trixie answered 6/12, 2016 at 15:32 Comment(1)
it's surprising that nobody is trying to implement this. I suppose this will still not be applicable if we want to mix EdgeNgramField and CharField? I am thinking about just modifying the queryset so that the default query is searched across different fieldsTallulah

© 2022 - 2024 — McMap. All rights reserved.