使用 Django 通过远程数据提高 Twitter 的 typeahead.js 性能

Posted

技术标签:

【中文标题】使用 Django 通过远程数据提高 Twitter 的 typeahead.js 性能【英文标题】:Improving Twitter's typeahead.js performance with remote data using Django 【发布时间】:2013-10-26 17:32:30 【问题描述】:

我有一个包含大约 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 sn-p 是因为没有它我的表单在按下回车时由于某种原因无法提交。

我的 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 模型中的短字段也被索引。有没有办法提高我的预输入性能?

【问题讨论】:

您能否使用浏览器的分析工具(Chrome 开发者工具或 Firebug)来查看 a) 您的请求何时发出以及 b) 它们花费了多长时间? 是的......就像我说的我的预输入请求的本地版本大约需要 1-2 秒。在 Heroku 上,它至少需要 2 秒,最长可达 8-9 秒。与较短的请求相比,较长的请求具有非常长的“等待”时间。 【参考方案1】:

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

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

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

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

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

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

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

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

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

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

HTH。

【讨论】:

对于您的点 1-2,ping 和值是正常的。 3. 我正在使用 heroku 来处理与数据库的连接。 4. 我不熟悉测试这些东西,所以我会调查一下。 5. 是的,我最近限制了输入及其返回的大小,它仍然很慢。谢谢你的意见,我会继续努力的。【参考方案2】:
        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 实例,最后从中读取单个属性。

【讨论】:

【参考方案3】:

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

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

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

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

如果不是这样,那么我可能会考虑记录 $('#navPersonSearch') 何时调用 typeahead:initializedtypeahead:opened 以查看它们是否会带来任何奇怪的东西。

【讨论】:

【参考方案4】:

您可以使用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')

【讨论】:

调试一个类似的问题,我发现了一个bug。在第 3 行,应该是:suggests = [result.object.first_name for result in sqs]

以上是关于使用 Django 通过远程数据提高 Twitter 的 typeahead.js 性能的主要内容,如果未能解决你的问题,请参考以下文章

企业im即时通讯软件支持移动办公,提高远程办公效率

有没有办法通过 ajax 提高正常的 Django 表单验证?

django cloudinary 通过 url 上传远程图像 - 文件名无效

企业im即时通讯软件支持移动办公,提高远程办公效率

无法使用便携式 Xampp 通过 Django 连接到 MySQL

云服务器的应用,提高业务绩效