使用Django利用远程数据改善Twitter的typeahead.js性能

时间:2013-10-18 01:24:06

标签: javascript python django django-views typeahead.js

我有一个大约有1.2M名字的数据库。当您输入某人的姓名时,我正在使用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片段是因为如果没有它,我的表单在推入时会因某些原因而无法提交。

我的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模型中的短字段也被编入索引。有没有办法改善我的先行者的表现?

4 个答案:

答案 0 :(得分:3)

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

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

1)从您的机器到Heroku的平均“ping”是多少?如果它很远,那就是额外的开销。但是并不多。当你指的是8-9秒时,肯定不会太多。注意,https的惩罚会更大。

2)检查waitLimitFn数据集中rateLimitWaitremote的值。它们是默认值吗?

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

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

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

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

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

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

HTH。

答案 1 :(得分: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)

通过这种方式,您可以直接从db获取单个字段,而不是:获取所有表行,从中创建Person实例,最后从中读取单个属性。

答案 2 :(得分:0)

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

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

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

如果是这种情况,那么我们将需要进入可能会减慢查询的速度,我的Python技能不存在所以我无法帮助你对不起!

如果情况并非如此,那么我可能会考虑在$('#navPersonSearch')调用typeahead:initializedtypeahead:opened时进行一些记录,看看它们是否会带来奇怪的结果。

答案 3 :(得分: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')