我使用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
答案 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的回答中的建议,并从索引文件中删除了所有下划线。