Django Haystack ElasticSearch:按匹配项的位置排序

3
我目前正在使用Django构建Web应用程序,并使用Haystack和ElasticSearch进行搜索实现。我已经成功地设置了它,但现在我正在努力实现正确的搜索结果排序。
我使用默认的es后端实现,并搜索文档包括游戏名称、俄语游戏名称和描述:
text = indexes.CharField(document=True, use_template=True)

#Document
{{ object.name }}
{{ object.name_ru }}
{{ object.description }}

我从以下查询中获取了搜索结果:
sqs=SearchQuerySet().models(Game).load_all()\
                                 .filter(content__startswith=query)

结果是预期的,但不是理想的。例如,如果我搜索“adv”,结果如下:

  1. 使命召唤:高级战争
  2. 胖公主历险记
  3. 探险活宝:芬恩与杰克的调查
  4. 妖精劍士F:冒險黑神力量

我想要的是按照游戏名称中以查询词开头的单词位置排序的结果,因此示例结果应如下所示:

  1. 探险活宝:芬恩与杰克的调查
  2. 胖公主历险记
  3. 使命召唤:高级战争
  4. 妖精劍士F:冒險黑神力量

请问有人可以指点我如何实现这个功能吗?谢谢!

更新!!! 请查看我的解决方案。

1个回答

2
我来翻译一下:

问题已经解决。

部分答案可以在此找到:stackoverflow.com/questions/27538766/scoring-by-term-position-in-elasticsearch -- 这里解释了如何重写评分以考虑术语位置,并构建查询以按该得分排序。

所需的是,为了使其与Django-Haystack配合使用,需要覆盖Haystack提供的Elasticsearch后端和SearchQuerySet。以下是我实现这一点的方式。

首先,从Haystack中需要的是:

  1. Produce correct mapping like this:

    "text" : {            
        "type" : "string",
        "index_options" : "offsets",
        "index_analyzer" : "edgengram_analyzer",
        "search_analyzer" : "standard_search"
      }
    

    When "index_options" set to "offsets" -- term offset saved in index so we can retrieve it later in scoring script.

  2. Build query that sorts by updated score. My query looked like this:

    {"query":{
             "match_phrase_prefix" : {"text" : text}
             },
     "sort": {
              "_script": {
                        "script_file": "score_script",
                        "type":"number",
                        "order": "asc",
                        "params": {"q": text}
                         }
             }
    }
    

    Script file "score_script" that provides updated scores looks like this:

    termInfo=_index["text"].get(q,_OFFSETS | _CACHE);
    for(pos in termInfo)
    {
    return _score+pos.startOffset
    };
    

首先,为了建立正确的映射,我们需要覆盖Haystack提供的ElasticSearch后端,这样我们就可以传递自定义参数,例如“index_options”。我的实现是基于elasticstack的——该项目允许为每个字段指定自定义分析器,比如:

    text = CharField(document=True, use_template=True,
        analyzer='stop')

这是我对elasticstack可配置后端的定制-- gist.github.com/GrigoriyMikhalkin/f76be703bc53380986a0#file-backend-py。它增加了一个'add'参数,接受形式为{parameter: value}的字典。例如:
    text = CharField(document=True, use_template=True,
                 analyzer="edgengram_analyzer",\
                 add={"search_analyzer":"standard_search",
                      "index_options":"offsets"})

要使用它,您需要在项目的settings.py中覆盖HAYSTACK_CONNECTIONS变量,如下所示:

    HAYSTACK_CONNECTIONS = {
    "default":{
       "ENGINE":
            "base.search_backend.backend.ConfigurableElasticSearchEngine",
       "URL": os.getenv("ELASTICSEARCH_URL", "http://127.0.0.1:9200/"),
       "INDEX_NAME": "haystack",
}

更多细节请参考elasticstack文档。

接下来要做的是构建正确的查询。它由两部分组成。首先,您需要创建一个脚本来进行重新评分(就像上面的脚本),并将其放置在ES的/config/scripts/目录中。

接下来是覆盖Haystack提供的默认SearchQuerySet。我的实现受到了这篇博客文章的启发: http://www.stamkracht.com/extending-haystacks-elasticsearch-backend/

我的实现(gist.github.com/GrigoriyMikhalkin/f76be703bc53380986a0#file-query-py)为SearchQuerySet添加了custom_search方法。它可以像这样使用:

    sqs = ConfigurableSearchQuerySet().models(Game).load_all()\
                                      .filter(content__startswith=q)\
                                      .custom_search(search_text=q)

My custom ElasticSearch Backend.


你把 'score_script' 文件放在哪里了? - Wingston Sharon
1
嗨,Wingston。我不记得我把 script_file 存储在哪里了。请尝试将其保存在 /etc/elasticsearch/scripts/etc/elasticsearch/config/scripts/ 中。此外,script 选项也可用,因此您可以直接将代码放入查询中。 - Grigoriy Mikhalkin
"/etc/elasticsearch/scripts" 是正确的位置。它还需要 .groovy 扩展名。谢谢! - Wingston Sharon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接