持久化

让我们看看一个简单的 Python 类,它代表博客系统中的文章

from datetime import datetime
from elasticsearch_dsl import Document, Date, Integer, Keyword, Text, connections

# Define a default Elasticsearch client
connections.create_connection(hosts="https://localhost:9200")

class Article(Document):
    title = Text(analyzer='snowball', fields={'raw': Keyword()})
    body = Text(analyzer='snowball')
    tags = Keyword()
    published_from = Date()
    lines = Integer()

    class Index:
        name = 'blog'
        settings = {
          "number_of_shards": 2,
        }

    def save(self, ** kwargs):
        self.lines = len(self.body.split())
        return super(Article, self).save(** kwargs)

    def is_published(self):
        return datetime.now() > self.published_from

# create the mappings in elasticsearch
Article.init()

# create and save and article
article = Article(meta={'id': 42}, title='Hello world!', tags=['test'])
article.body = ''' looong text '''
article.published_from = datetime.now()
article.save()

article = Article.get(id=42)
print(article.is_published())

# Display cluster health
print(connections.get_connection().cluster.health())

在这个例子中,你可以看到

  • 提供默认连接

  • 使用映射配置定义字段

  • 设置索引名称

  • 定义自定义方法

  • 覆盖内置的 .save() 方法,以便在持久化生命周期中进行挂钩

  • 检索对象并将其保存到 Elasticsearch 中

  • 访问底层客户端以使用其他 API

你可以在 持久化 章节中了解更多信息。

根据查询更新

让我们继续讨论博客文章的简单示例,并假设每篇文章都有一个点赞数。在这个例子中,假设我们想要将所有匹配特定标签且不匹配特定描述的文章的点赞数增加 1。如果将其写成一个 dict,我们将有以下代码

from elasticsearch import Elasticsearch
client = Elasticsearch()

response = client.update_by_query(
    index="my-index",
    body={
      "query": {
        "bool": {
          "must": [{"match": {"tag": "python"}}],
          "must_not": [{"match": {"description": "beta"}}]
        }
      },
      "script"={
        "source": "ctx._source.likes++",
        "lang": "painless"
      }
    },
  )

使用 DSL,我们现在可以这样表达这个查询

from elasticsearch import Elasticsearch
from elasticsearch_dsl import Search, UpdateByQuery

client = Elasticsearch()
ubq = UpdateByQuery(using=client, index="my-index") \
      .query("match", title="python")   \
      .exclude("match", description="beta") \
      .script(source="ctx._source.likes++", lang="painless")

response = ubq.execute()

正如你所见,Update By Query 对象提供了 Search 对象提供的许多节省,此外还允许根据以相同方式分配的脚本更新搜索结果。

elasticsearch-py 迁移

你无需将整个应用程序移植到 Python DSL 才能获得它的好处,你可以从现有 dict 创建一个 Search 对象,使用 API 修改它,然后将其序列化回 dict

body = {...} # insert complicated query here

# Convert to Search object
s = Search.from_dict(body)

# Add some filters, aggregations, queries, ...
s.filter("term", tags="python")

# Convert back to dict to plug back into existing code
body = s.to_dict()