4

我有一个大约有 120 万个名字的数据库。当您键入某人的姓名时,我正在使用 Twitter 的 typeahead.js 远程获取自动完成建议。在我的本地环境中,在您停止输入后大约需要 1-2 秒才能显示结果(在您输入时自动完成不会出现),并且在 Heroku 上部署的应用程序上需要 2-5 秒以上(仅使用 1 dyno )。

我想知道它仅在您停止输入(并延迟几秒钟)后才显示建议的原因是否是因为我的代码没有经过优化?

页面上的脚本:

<script type="text/javascript">
$(document).ready(function() {
  $("#navPersonSearch").typeahead({
    name: 'people',
    remote: 'name_autocomplete/?q=%QUERY'
  })
    .keydown(function(e) {
        if (e.keyCode === 13) {
            $("form").trigger('submit');
        }
    });
});
</script> 

keydown 片段是因为没有它,我的表单在按 Enter 时由于某种原因无法提交。

我的 Django 视图:

def name_autocomplete(request):
    query = request.GET.get('q','')
    if(len(query) > 0):
        results = Person.objects.filter(short__istartswith=query)
        result_list = []
        for item in results:
            result_list.append(item.short)
    else:
        result_list = []

    response_text = json.dumps(result_list, separators=(',',':'))
    return HttpResponse(response_text, content_type="application/json")

我的 Person 模型中的 short 字段也被索引。有没有办法提高我的预输入性能?

4

4 回答 4

3

我不认为这与 Django 直接相关,但我可能错了。对于这种情况,我可以提供一些通用的建议:

(我的钱在下面的#4 或#5 上)。

1) 从您的机器到 Heroku 的平均“ping”是多少?如果它很远,那就有点额外的开销。不过不多。与您所指的 8-9 秒相比,当然不多。请注意,使用 的惩罚会更大https

2)检查数据集中waitLimitFnrateLimitWait的值remote。他们是默认的吗?

3)很可能,问题与数据库/数据集有关。首先要检查的是建立与数据库的连接需要多长时间(您是否使用连接池?)。

4)第二件事:运行查询需要多长时间。我的赌注是在这一点或下一个。添加调试打印,或使用 NewRelic(即使是免费计划也可以)。查看生成的查询并确保它已编入索引。让您的数据库“解释”此类查询的执行计划并使其使用索引。

5)第三件事:结果大吗?例如,如果您指定“J”作为查询,我想会有很多答案。只是获取它们并将它们流式传输到客户端将需要时间。在这种情况下:

5.1) 为您的数据集指定 a minLength。如果不是 4,则至少为 3。

5.2) 限制您的数据库查询返回的结果集。让它返回不超过 10,比如说。

6) 我不是 Django 专家,但请确保您在 Django 中使用模型的方式不会使其首先将整个表加载到内存中。只是在说'。

HTH。

于 2013-10-18T06:27:36.180 回答
1
        results = Person.objects.filter(short__istartswith=query)
        result_list = []
        for item in results:
            result_list.append(item.short)

可能不是您运行缓慢的唯一原因,但从性能的角度来看这很可怕:永远不要循环 django 查询集。要从 django 查询集中组装一个列表,您应该始终使用 values_list。在这种特定情况下:

        results = Person.objects.filter(short__istartswith=query)
        result_list = results.values_list('short', flat=True)

这样您就可以直接从数据库中获取您需要的单个字段,而不是:获取所有表行,从中创建一个 Person 实例,最后从中读取单个属性。

于 2015-01-19T15:09:29.433 回答
0

Nitzan 涵盖了许多可以提高性能的要点,但与他不同的是,我认为这可能与 Django 直接相关(至少,服务器端)。

测试这一点的一种快速方法是更新您的name_autocomplete方法,以简单地以 Typeahead 期望的格式返回 10 个随机生成的字符串。(我们希望它们随机的原因是 Typeahead 的缓存不会扭曲任何结果)。

我怀疑您会看到 Typeahead 现在运行得非常快,您应该minLength在输入字符串后立即开始看到结果。

如果是这种情况,那么我们将需要研究可能会减慢查询速度的原因,我的 Python 技能不存在,所以我无法为您提供帮助,抱歉!

如果不是这种情况,那么我可能会考虑对何时$('#navPersonSearch')调用进行一些记录typeahead:initializedtypeahead:opened看看它们是否会带来任何奇怪的东西。

于 2013-10-20T11:14:04.597 回答
0

您可以使用django haystack,您的服务器端代码大致如下:

def autocomplete(request):
sqs = SearchQuerySet().filter(content_auto=request.GET.get('q', ''))[:5]  # or how many names you need
suggestions = [result.first_name for result in sqs]
# you have to configure typeahead how to process returned data, this is a simple example
data = json.dumps({'q': suggestions})  
return HttpResponse(data, content_type='application/json')
于 2013-11-01T18:58:01.810 回答