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.

Danny Beckett
  • 20,529
  • 24
  • 107
  • 134
Pooria Kaviani
  • 748
  • 1
  • 8
  • 17

2 Answers2

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
Mark Chackerian
  • 21,866
  • 6
  • 108
  • 99
  • 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... – Cerin Oct 18 '12 at 15:09
  • Just to be clear, this is an example that was written for Haystack 1.2 – Mark Chackerian Nov 10 '12 at 19:48
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
hedleyroos
  • 320
  • 3
  • 9
  • 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 fields – Forethinker Jan 11 '18 at 01:17