如何从Python提高Easticsearch的查询准确性?

时间:2017-02-18 02:29:25

标签: python elasticsearch

如何使用Python包装器提高Elasticsearch的准确性搜索结果?我的基本示例返回结果,但结果非常不准确。

我在Ubuntu 16上运行Elasticsearch 5.2,我首先创建索引并添加一些文档,如:

es = Elasticsearch()
# Document A
es.index(
    index='my-test-index',
    doc_type='text',
    body=dict(
        search_key='some specific keywords',
        weight=1.0,
        data='blah1',
    ),
)
# Document B
es.index(
    index='my-test-index',
    doc_type='text',
    body=dict(
        search_key='some other specific keywords',
        weight=1.0,
        data='blah2',
    ),
)
# Document C
es.index(
    index='my-test-index',
    doc_type='text',
    body=dict(
        search_key='some other very long text that is very different yet mentions the word specific and keywords',
        weight=1.0,
        data='blah3',
    ),
)

然后我用以下方式查询:

es = Elasticsearch()
es.indices.create(index='my-test-index', ignore=400)
query = 'some specific keywords'
results = es.search(
    index='my-test-index',
    body={
        'query':{
            "function_score": {
                "query": {  
                    "match": {
                        "search_key": query
                    }
                },
                "functions": [{
                    "script_score": { 
                        "script": "doc['weight'].value"
                    }
                }],
                "score_mode": "multiply"
            }
        },
    }
)

虽然它返回所有结果,但它按文档B,C,A的顺序返回它们,而我希望它们按顺序A,B,C,因为尽管所有文档都包含我的所有关键字,但只有第一个是完全匹配。我希望C是最后一个,因为即使它包含我的所有关键字,它也包含很多我没有明确搜索的漏洞。

当我索引更多条目时,此问题会更复杂。搜索会从我的查询中返回包含单个关键字的所有内容,并且看起来相同地对它们进行加权,导致搜索结果越小,我的索引越大,搜索结果就越准确。

这使得Elasticsearch几乎无用。无论如何我能解决它吗?我的search()电话有问题吗?

2 个答案:

答案 0 :(得分:2)

在您的查询中,您可以使用match_phrase查询而不是match查询,以便搜索字词的顺序和接近度进入混合状态。此外,您可以添加较小的slop,以便使条款更加分开或以不同的顺序排列。但是,具有相同顺序和更近距离的条款的文档将比具有不按顺序和/或更远的条款的文档排名更高。试一试

            "query": {  
                "match_phrase": {
                    "search_key": query,
                    "slop": 10
                }
            },

注意:slop是一个数字,表示您需要执行多少"swaps"个搜索字词才能登陆文档中的术语配置。

答案 1 :(得分:0)

很抱歉没有仔细阅读您的问题以及下面加载的答案。我不想在泥泞中坚持下去,但我认为如果你更了解Elasticsearch本身是如何运作的话会更清楚。

由于您索引文档而未指定任何索引和mapping配置,因此Elasticsearch将使用它提供的几个默认设置。索引过程将首先使用standard tokenizer对文档中的字段值进行标记,然后使用the standard analyzer对其进行分析,然后将其存储在索引中。标准标记器和分析器都通过基于字边界分割字符串来工作。因此,在索引时间结束时,您在search_key字段中的字词索引中的内容为["some", "specific", "keywords"],而不是"some specific keywords"

在搜索时间内,match查询使用称为术语频率/反向文档频率或TF / IDF的相似性算法来控制relevance。这种算法在文本搜索中非常流行,并且有一个维基百科章节:https://en.wikipedia.org/wiki/Tf%E2%80%93idf。这里需要注意的重要一点是,您的术语出现在索引中的频率越高,相关性就越不重要。 somespecifickeywords出现在索引中的所有3个文档中,因此就弹性搜索而言,它们对文档在搜索中的相关性贡献很小结果。由于A仅包含这些字词,因此在英文索引中只包含theana的文档。即使您专门搜索theana,它也不会显示为第一个结果。 B排名高于C,因为B较短,产生较高的标准值。该相关文档中解释了该范数值。这对我来说有点猜测,但如果您使用explain API解释查询,我认为它确实有效。

那么,回到你的需要,如何支持完全匹配而不是其他一切?当然,Val指出了match_phrase查询。另一种流行的方法(我个人更喜欢)是在定义映射时使用search_key.raw选项在名为not_analyzed的嵌套字段中索引原始值:https://www.elastic.co/guide/en/elasticsearch/guide/current/mapping-intro.html#_index_2并简单地将其提升搜索时的原始值。