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

时间:2015-11-18 19:47:17

标签: python django elasticsearch django-haystack

我目前正在Django上构建webapp,并使用Haystack和ElasticSearch进行搜索实现。我成功地设置了它,但现在我正在努力实现正确的搜索结果顺序。

我使用默认es后端实现,搜索文档包含游戏名称,俄罗斯游戏的名称和描述:

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

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

我从以下查询中获取了SearchResult:

sqs=SearchQuerySet().models(Game).load_all()\
                                 .filter(content__startswith=query)

结果是预期的但不是理想的结果。例如,如果我通过' adv'结果是:

  1. 使命召唤:高级战争
  2. Fat Princess Adventures
  3. 冒险时间:芬恩&杰克调查
  4. Fairy Fencer F:Advent Dark Force
  5. 我想要的是按照游戏名称中的单词位置(以查询开头)排序的结果,因此示例结果应如下所示:

    1. 冒险时间:芬恩&杰克调查
    2. Fat Princess Adventures
    3. 使命召唤:高级战争
    4. Fairy Fencer F:Advent Dark Force
    5. 拜托,有人能指出我如何实现这一目标。提前谢谢!

      UPDATE !!! 请参阅下面的解决方案。

1 个答案:

答案 0 :(得分:2)

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

为了使它与Django-Haystack一起使用,你需要覆盖Haystack提供的Elasticsearch Backend和SearchQuerySet。以下是我对此的实现。

首先,Haystack需要的是:

  1. 按如下方式生成正确的映射:

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

    当" index_options"设置为"偏移" - 在索引中保存的术语偏移量,以便我们稍后在评分脚本中检索它。

  2. 构建按更新得分排序的查询。我的查询看起来像这样:

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

    脚本文件" score_script"提供更新的分数如下所示:

    termInfo=_index["text"].get(q,_OFFSETS | _CACHE);
    for(pos in termInfo)
    {
    return _score+pos.startOffset
    };
    
  3. 首先是第一件事。要构建正确的映射,我们需要覆盖Haystack提供的ElasticSearch后端,因此我们可以传递自定义参数,例如" index_options"。我的实现基于elasticstack - 项目,允许为每个字段指定自定义分析器,如下所示:

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

    这是我对elasticstack可配置后端的定制 - gist.github.com/GrigoriyMikhalkin/f76be703bc53380986a0#file-backend-py。它增加了添加'接受形式字典的参数 - {parameter:value}。例如:

        text = CharField(document=True, use_template=True,
                     analyzer="edgengram_analyzer",\
                     add={"search_analyzer":"standard_search",
                          "index_options":"offsets"})
    

    要使用它,你需要在tour项目的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)将custom_search方法添加到SearchQuerySet。它可以像这样使用:

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

    My custom ElasticSearch Backend.