使用 Django 连接 Elasticsearch
这是2014年Elasticsearch圣诞日历的第24篇文章。
2019年12月3日更新
由于ElasticUtils开发已经终止,而haystack开发也停滞不前,因此现在使用Elasticsearch官方的elasticsearch-dsl-py是最佳选择。
序言
如果使用Django来实现搜索功能,我认为会使用标准的ORM,即QuerySet。然而,由于通过ORM向数据库发出查询,所以当数据量达到几十万条或跨越多个模型进行搜索时,JOIN操作会增多,性能会受到影响。
当然之言当然是这样的。
所以,一种解决方案是在搜索后端引入Elasticsearch。
在这里,我想介绍一些在Django中引入Elasticsearch的方法。
Python使用Elasticsearch库
使用 Haystack
Haystack为多个搜索后端提供了类似Django的QuerySet的API。
由于可以使用类似于标准ORM代码的方式来发出搜索查询,请不需要记住每个搜索引擎的查询DSL,从而降低了学习成本。
如果参考以下的文章,你应该大致了解如何使用了。
-
- Django + Elasticsearch コトハジメ
- Haystack + Elasticsearch + kuromoji コトハジメ
如果在Django的settings.py文件中使用elasticstack扩展设置Elasticsearch配置,或者使用celery-haystack使用任务队列的Celery,还可以扩展功能,以实现Django模型在更新时异步更新Elasticsearch索引等功能扩展。
干草堆的注意事项
由于长时间没有更新Elasticsearch的后端,尽管Haystack拥有丰富的周边库并且非常方便,但需要注意以下几点在引入时。
-
- Aggregation が使えない
Facet のみ対応
Haystack 全体で1つの Index しか生成しない
複数の Index にドキュメントを分けることができない
由于基本不支持Elasticseach 1.0迁移的新功能,因此许多功能受到了限制。特别是不能使用聚合功能非常令人痛苦。
根据以上内容,在使用Django的Haystack时,需要遵循以下方针。
-
- Elasticsearch の集計機能を使用する場合 Haystack は 使わない
ドキュメントを複数の Index に分ける場合 Haystack は 使わない
如果你只专注于简单的全文搜索,Haystack也可以满足需求。
然而,随着搜索功能的不断增加,很难想象仅仅依靠全文搜索就能满足功能需求的情况。而且由于Haystack与使用的Django应用程序紧密耦合,因此当需要放弃Haystack时,会带来相当大的负担。
此外,保存的文档数据也将采用Haystack独特的格式,因此很难继承已生成的索引数据或在其他搜索后端中重用。
使用ElasticUtils
這是Mozilla為Python設計的Elasticsearch庫。
順帶一提,Mozilla經營著一個龐大的Django網站(網址)。
实际上,我从未使用过 elasticutil,对于它的实际使用感受、便利性以及可能遇到的困难,我一无所知(很抱歉)。
因此,我想要通過閱讀文件並寫下我的印象。
-
- Django 専用ではない
他のPythonプロジェクトにも適用可能
ElasticUtils.contrib モジュールで対応可能(URL)
Django の Model と連携可能
Celery との連携可能
検索APIがQuerySetに似てる
Haystack ほどではない
S() オブジェクトで検索クエリを発行する
Django の QuerySet と同じ立ち位置
Q() オブジェクトで検索条件を個別に定義して S() へ渡せる
条件によって変化する複雑なクエリの組み立てに使える
F() オブジェクトでフィルタの or 検索ができる
Django の Q と似た用途
Index と mapping は個別に定義できる
最新の Aggregation に対応しているか怪しい
実際に発行されるQueryDSLやソースの中身を確認していないので断言はできませんが、ドキュメントのURLのリンク先が Facet のままなので Es の集計機能に対応していない可能性があり注意が必要です。
http://ElasticUtils.readthedocs.org/en/latest/searching.html#id46
印象
ElasticUtils虽然不像Haystack那样功能受限,但其各种API都有适度的抽象化,给人一种比Haystack更灵活可调用的印象。此外,ElasticUtils的API与Django的API有很多相似之处,对于习惯编写QuerySet代码的人来说应该更容易上手。不过需要注意的是,由于其可能不支持聚合功能,因此在需要使用聚合功能时需要格外小心。
使用elasticsearch-py
这是Elasticsearch提供的官方库。
-
- Python を Elasticsearch の薄いラッパー
-
- PythonのDictでそのまま QueryDSL を書くため、QueryDSLを覚える必要がある
- 依存が少なく、Esの仕様を知っていればフル機能を呼び出せる
这个库只是将调用 REST API 和接收返回值的部分隐藏起来,所以只是让你能够在Python中写入通常用curl实现的部分,这就是我的印象。
由于需要记住Elasticsearch各种API,学习成本将变得很高。此外,代码量也会增加。
然而,以下是它的好处:
– 可轻松追随Elasticsearch的更改
– 可轻松尝试新功能
如果对于引入 Elasticsearch 有足够的时间余裕,那么这将是最灵活的方式。
总结
我們考慮使用Django對Elasticsearch進行連接的方針如下。
-
- Elasticsearch の全文検索機能のみしか今後つかうことがなく Haystack で十分まかなえる
複雑な検索クエリもHaystackだとそこそこ楽に書ける
Elasticsearch 向けのバックエンドを自分で書き変えて拡張する覚悟があるなら非常に優秀なライブラリ
Haystackほどの抽象化を求めないなら ElasticUtils
Haystack より柔軟性はありそう
集計機能を使う予定ならばドキュメントやソースを要確認
Elasticsearch の機能を積極的に利用し, 導入まで余裕があるなら elasticsearch-py
作業工数は高いが、結局のところ利用方法に最も柔軟性がある
根据所需功能和引入的时间余地,由于在Haystack上曾经遇到一些困难,所以个人倾向于尽量不使用Haystack,而是考虑使用ElasticUtils。
如果想要使用Elasticsearch强大的聚合功能,可能会发现ElasticUtils也很困难,因此可能会选择使用官方模块elasticsearch-py。
文献引用
http://pixabay.com/ja/blog/posts/django-search-with-elasticsearch-47/
Django サイトで Elasticsearch を導入する際の検討結果が書かれています。この記事はもっと極端で elasticsearch-py も使わず requests を使った JSONベース HTTPリクエストを直接投げるという結論の落ち着いています。
最初に箇条書きで検討結果がまとめられていて参考になります。Django 製のサイトに検索エンジンを導入する際には一読をおすすめします。
http://blog.kevinastone.com/elasticsearch-bliss-with-elasticutils.html
ElasticUtils の使い方
http://www.stamkracht.com/extending-haystacks-elasticsearch-backend/
Haystack のクエリ拡張方法について書かれています