Django-haystack按标题排序结果

时间:2011-09-13 09:51:39

标签: django solr django-haystack

我想按标题对我的django-haystack查询的结果进行排序。

from haystack.query import SearchQuerySet
for result in SearchQuerySet().all().order_by('result_title_sort'):
    print result.result_title_sort

但是我一直收到这个错误:

  

字段“result_title_sort”中的字词多于文档,但是无法对标记化字段进行排序

这是我的草堆场定义:

result_title_sort = CharField(indexed=True, model_attr='title')

我该如何定义字段,以便对其进行排序?

5 个答案:

答案 0 :(得分:5)

谢谢Mark Chackerian,您的解决方案确实可以用于排序。但是我仍然觉得修改自动生成的schema.xml的输出有点不舒服。我通过使用Solr的< dynamicField> 字段类型找到了解决方案。关于如何使用动态字段,Django-Haystack文档并不是很明确,但基本上如果你只是在dict SearchIndex返回的prepare()中包含一个新密钥并且会在索引时将dynamicField添加到文档中。

SearchIndex

中删除现有属性
#result_title_sort = CharField(indexed=True, model_attr='title') 
def prepare(self, obj):
    prepared_data['result_title_sort_s'] #notice the "_s"

以上内容将在名为result_title_sort_s的文档中创建一个动态字符串字段,您可以通过该字段对结果进行排序。

答案 1 :(得分:3)

您需要确保您的排序字段在SOLR中是非标记化的。从Haystack文档中可以看出如何使用Haystack进行非标记化。我的解决方案是更改Haystack生成的SOLR schema.xml,使字段类型为“ string ”而不是“ text ”。所以不要在schema.xml中使用这样的东西:

<field name="result_title_sort" type="text" indexed="true" stored="true" multiValued="false" />

你需要这个:

<field name="result_title_sort" type="string" indexed="true" stored="true" multiValued="false" />

由于您可能多次重新生成schema.xml,因此我建议您创建一个构建脚本来创建架构文件,该文件将自动为您更改架构。像这样:

./manage.py build_solr_schema | sed 's/<field name=\"result_title_sort\" type=\"text\"/<field name=\"result_title_sort\" type=\"string\"/' > schema.xml

(或Haystack 2.0)

./manage.py build_solr_schema | sed 's/<field name=\"name_sort\" type=\"text_en\"/<field name=\"name_sort\" type=\"string\"/' > schema.xml

在我这样做之后,我的排序按字母顺序排列。但是,仍然存在一些问题,因为排序是ASCII顺序,它将小写和非罗马字符放在最后。所以我创建了以下方法来准备排序文本,它使用unidecode模块将非罗马字符转换为ASCII。它还删除了初始空格“the”和“a”:

def format_text_for_sort(sort_term,remove_articles=False):
    ''' processes text for sorting field:
        * converts non-ASCII characters to ASCII equivalents
        * converts to lowercase
        * (optional) remove leading a/the
        * removes outside spaces
    '''
    sort_term = unidecode(sort_term).lower().strip()
    if remove_articles:
        sort_term =  re.sub(r'^(a\s+|the\s+)', '', sort_term )
    return sort_term

然后你需要在你的search_indexes.py中添加一个prepare方法来调用格式化程序,比如

def prepare_result_title_sort(self,obj):
    return format_text_for_sort( obj.title, remove_articles=True )

答案 2 :(得分:2)

最后,我通过滥用faceted=True找到了解决方法。它会导致haystack为charfield生成type="string"字段。它是SOLR schema.xml中唯一发生变化的东西

result_title_sort = CharField(indexed=True, faceted=True)

def prepare_result_title_sort(self, article):
    return slugify(article.title.lower())

现在可以对结果进行排序:

results = results.order_by('result_title_sort_exact')

答案 3 :(得分:1)

如果字符串被标记化(即有空格),Solr将不允许您对字符串列进行排序。我希望你的标题有多个标记(单词),因此错误。

“字符串术语值可以包含任何有效的字符串,但不应该被标记化。值将根据其自然顺序排序。”来自http://lucene.apache.org/java/3_0_3/api/core/org/apache/lucene/search/Sort.html

答案 4 :(得分:0)

只是接受了接受的答案,我发现只需使用FacetCharField而不是CharField来处理我想要排序的文本就足以将其作为字符串输出到模式中,从而使其可以排序。

我对haystack / Solr相当新,所以我不确定使用FacetCharField的其他含义,但这对我有用。