干草堆多个字段搜索

5 投票
2 回答
3678 浏览
提问于 2025-04-16 02:42

你好,我正在使用Haystack和Woosh作为搜索引擎:

我的模型看起来是这样的:

class Person(models.Model):
    personid = models.IntegerField(primary_key = True, db_column = 'PID')  
    firstname = models.CharField(max_length = 50, db_column = 'FIRSTNAME')  
    lastname = models.CharField(max_length = 50, db_column = 'LASTNAME') 
    class Meta:
        db_table = '"TEST"."PERSON"'
        managed = False


class TDoc(models.Model):
    tdocid = models.IntegerField(primary_key = True, db_column = 'TDOCID')  
    person = models.ForeignKey(Person, db_column = 'PID')
    content = models.TextField(db_column = 'CONTENT', blank = True) 
    filepath = models.TextField(db_column = 'FILEPATH', blank = True) 
    class Meta:
        db_table = '"TEST"."TDOC"'
        managed = False

search_index.py的内容如下:

class TDocIndex(SearchIndex):

    content = CharField(model_attr = 'content', document = True)
    filepaht = CharField(model_attr = 'filepath')
    person = CharField(model_attr = 'person')

    def get_queryset(self):
        return TDoc.objects.all()

    def prepare_person(self, obj):
        # Store a list of id's for filtering
        return obj.person.lastname

site.register(TDoc, TDocIndex)

我的问题是,我想进行多个字段的搜索,比如:

content:xxx AND person:SMITH

在Haystack中,它会一次性搜索所有字段,我无法进行特定字段的搜索。我怀疑我的索引可能有问题,但:

ix = open_dir("/testindex")

searcher = ix.searcher()

mparser = MultifieldParser(["content", "filepath", "person"], schema = ix.schema)
myquery = mparser.parse(content:xxx AND person:SMITH')
results = searcher.search(myquery)
for result in results:
    print result

实际上它是可以工作的,并且返回了正确的值。我使用的是教程中的标准Haystack SearchView和search.html。

(r'^search/', include('haystack.urls')),

2 个回答

0

你可以在你的索引类里这样使用 prepare 方法:

from apps.main.models import Person
from haystack import indexes


class PersonIndex(indexes.SearchIndex, indexes.Indexable):
    text = indexes.CharField(document=True)
    lastname = indexes.CharField(null=True)

    date_insert = indexes.DateTimeField(model_attr="date_insert", indexed=False)
    date_update = indexes.DateTimeField(model_attr="date_update", indexed=False)

    def get_model(self):
        return Person

    def get_updated_field(self):
        return "date_update"

    def index_queryset(self, using="default"):
        return self.get_model().objects.all()

    def prepare(self, obj: Person):
        data = super().prepare(obj)

        main_fields = [obj.content, obj.filepath, obj.person.lastname]
        data["text"] = "\n".join(f"{col}" for col in main_fields)
        data["lastname"] = obj.person.lastname.lower()

        return data
5

在你的索引中,你需要定义一个字段,并设置为 document=True,这个字段就是 haystack 要搜索的内容。通常这个字段叫做 text。如果你打算根据其他字段的值进行过滤或排序,你可以添加额外的字段。

如果你想在搜索时考虑多个字段,可以把文档定义为一个模板,并在你的文档字段上设置 use_template。你的索引看起来会像这样:

class TDocIndex(SearchIndex):

    text = CharField(document=True, use_template=True)

    #if you plan to filter by person
    personid = IntegerField(model_attr='person__id') 

site.register(TDoc, TDocIndex)

然后你会有一个搜索/indexes/tdoc_text.txt 的模板,内容类似于:

{{ object.content }}
{{ object.filepath }}
{{ object.person.lastname }}

可以参考 这个回答。

撰写回答