无法在Django Haystick / Elasticsearch中找到不是单词的字符串

时间:2016-07-09 20:00:11

标签: django elasticsearch django-haystack

我使用Django Haystack和Elasticsearch作为实时飞行地图服务的后端。

我已正确设置了所有搜索索引,但是,我无法返回不是完整字词的搜索结果(例如航空呼号,其中一些采用样式{{1} },其他包括完整的单词,如N346IF)。 Speedbird 500查询样式不会产生任何结果,而我可以轻松返回后一个示例的结果。

我的查询如下:

N346IF

(请注意,在过去我使用了queryResults = SearchQuerySet().filter(content=q) # where q is the query in string format 查询集,但是文档列出了它只跟踪单词,因此我现在传递一个原始字符串。)

我的搜索索引字段设置为AutoQuery,带有搜索模板。

我有一个带有以下索引设置的自定义后端(以及EdgeNgramField分析器和snowball分析器):

pattern

我的后端配置为:

ELASTICSEARCH_INDEX_SETTINGS = {
    'settings': {
        "analysis": {
            "analyzer": {
                "ngram_analyzer": {
                    "type": "custom",
                    "tokenizer": "lowercase",
                    "filter": ["haystack_ngram"]
                },
                "edgengram_analyzer": {
                    "type": "custom",
                    "tokenizer": "lowercase",
                    "filter": ["haystack_edgengram"]
                }
            },
            "tokenizer": {
                "haystack_ngram_tokenizer": {
                    "type": "nGram",
                    "min_gram": 4,
                    "max_gram": 15,
                },
                "haystack_edgengram_tokenizer": {
                    "type": "edgeNGram",
                    "min_gram": 4,
                    "max_gram": 15,
                    "side": "front"
                }
            },
            "filter": {
                "haystack_ngram": {
                    "type": "nGram",
                    "min_gram": 4,
                    "max_gram": 15
                },
                "haystack_edgengram": {
                    "type": "edgeNGram",
                    "min_gram": 4,
                    "max_gram": 15
                }
            }
        }
    }
}

ELASTICSEARCH_DEFAULT_ANALYZER = "pattern"

为了成功获得两种和/或class ConfigurableElasticBackend(ElasticsearchSearchBackend): def __init__(self, connection_alias, **connection_options): super(ConfigurableElasticBackend, self).__init__( connection_alias, **connection_options) user_settings = getattr(settings, 'ELASTICSEARCH_INDEX_SETTINGS') if user_settings: setattr(self, 'DEFAULT_SETTINGS', user_settings) class ConfigurableElasticBackend(ElasticsearchSearchBackend): DEFAULT_ANALYZER = "pattern" def __init__(self, connection_alias, **connection_options): super(ConfigurableElasticBackend, self).__init__( connection_alias, **connection_options) user_settings = getattr(settings, 'ELASTICSEARCH_INDEX_SETTINGS') user_analyzer = getattr(settings, 'ELASTICSEARCH_DEFAULT_ANALYZER') if user_settings: setattr(self, 'DEFAULT_SETTINGS', user_settings) if user_analyzer: setattr(self, 'DEFAULT_ANALYZER', user_analyzer) def build_schema(self, fields): content_field_name, mapping = super(ConfigurableElasticBackend, self).build_schema(fields) for field_name, field_class in fields.items(): field_mapping = mapping[field_class.index_fieldname] if field_mapping['type'] == 'string' and field_class.indexed: if not hasattr(field_class, 'facet_for') and not \ field_class.field_type in('ngram', 'edge_ngram'): field_mapping['analyzer'] = self.DEFAULT_ANALYZER mapping.update({field_class.index_fieldname: field_mapping}) return (content_field_name, mapping) class ConfigurableElasticSearchEngine(ElasticsearchSearchEngine): backend = ConfigurableElasticBackend 样式字符串的搜索模式的结果,正确的设置是什么?

感谢任何输入,如果这与另一个问题相似(无法找到与之相关的任何内容),请道歉。

solarissmoke请求

编辑:,这个模型的架构:

N346IF

文字索引为:

class FlightIndex(indexes.SearchIndex, indexes.Indexable):
    text = indexes.EdgeNgramField(document=True, use_template=True)
    flight = indexes.CharField(model_attr='flightID')
    callsign = indexes.CharField(model_attr='callsign')
    displayName = indexes.CharField(model_attr='displayName')
    session = indexes.CharField(model_attr='session')

    def prepare_session(self, obj):
        return obj.session.serverId

    def get_model(self):
        return Flight

2 个答案:

答案 0 :(得分:1)

它没有完全解释您所看到的行为,但我认为问题在于您如何为数据建立索引 - 特别是text字段(当您过滤{{1时}})。

获取您提供的示例数据,呼号content,航班名称N133TC。此数据的Shahrul Nizam文档变为:

text

您已将此字段设置为flight___N133TC___Shahrul Nizam (最少4个字符,最多15个字符)。下面是索引此文档时生成的ngrams(为简单起见,我忽略了小写过滤器):

EdgeNgramField

请注意,标记生成器不会在下划线上拆分。现在,如果您搜索flig fligh flight flight_ flight___ flight___N flight___N1 flight___N13 flight___N133 flight___N133T flight___N133TC Niza Nizam ,则上述令牌都不会匹配。 (我无法解释为什么N133TC有效...它不应该,除非我错过了某些内容,或者在该字段的开头有空格。)

如果您将Shahrul文档更改为:

text

然后索引的标记将是:

flight N133TC Shahrul Nizam

现在,搜索flig flight N133 N133T N133TC Shah Shahr Shahru Shahrul Niza Nizam 应该匹配。

另请注意,文档中的N133TC字符串会产生一大堆(很可能)无用的令牌 - 除非这是故意的,否则没有它会更好。

答案 1 :(得分:0)

解决我自己的问题 - 欣赏solarissmoke的输入,因为它帮助我找出造成这种情况的原因。

我的回答是基于Greg Baker对这个问题的回答 ElasticSearch: EdgeNgrams and Numbers

问题似乎与在搜索文本中使用数值有关(在我的例子中,是N133TC模式)。请注意,在切换到snowball之前,我首先使用的是pattern分析器 - 这些都不起作用。

我在settings.py调整了我的分析仪设置:

"edgengram_analyzer": {
    "type": "custom",
    "tokenizer": "standard",
    "filter": ["haystack_edgengram"]
}

从而将tokenizer值从原来使用的standard分析器更改为lowercase

然后我将默认分析器设置为我的后端使用edgengram_analyzer(也在settings.py上):

ELASTICSEARCH_DEFAULT_ANALYZER = "edgengram_analyzer"

这就是诀窍!它仍然可以作为EdgeNgram字段使用,但也允许我的数值正确返回。

我也遵循solarissmoke的回答中的建议,并从索引文件中删除了所有下划线。