Elasticsearch DSL

Elasticsearch dsl是一个高级库,其目标是帮助编写 针对Elasticsearch运行查询。它建在官方建筑的顶上 低级客户端(elasticsearch-py).

它提供了一种更方便、更惯用的编写和操作方式 查询。它与Elasticsearch JSON DSL保持密切关系,反映了它的 术语和结构。它公开了Python中的整个DSL范围 直接使用定义的类或类似查询集的表达式。

它还提供了一个可选的包装器,用于将文档作为Python使用 对象:定义映射、检索和保存文档、包装 在用户定义的类中记录数据。

要使用其他Elasticsearch API(例如,群集运行状况)只需使用 底层客户端。

示例

请参阅示例目录查看一些复杂的示例,使用elasticsearch-dsl.

兼容性

该库与所有Elasticsearch版本兼容,因为2.x但是你必须使用匹配的主版本:

For Elasticsearch 7.0.之后,使用主要版本7(7.x.y))的 库。

For Elasticsearch 6.0.之后,使用主要版本6(6.x.y))的 库。

For Elasticsearch 5.0之后,使用主要版本5(5.x.y))的 库。

For Elasticsearch 2.0之后,使用主要版本2(2.x.y))的 库。

在中设置要求的推荐方式setup.py or requirements.txt is:

# Elasticsearch 7.x
elasticsearch-dsl>=7.0.0,<8.0.0

# Elasticsearch 6.x
elasticsearch-dsl>=6.0.0,<7.0.0

# Elasticsearch 5.x
elasticsearch-dsl>=5.0.0,<6.0.0

# Elasticsearch 2.x
elasticsearch-dsl>=2.0.0,<3.0.0

发展正在发生在master,较老的分支机构只获得错误修复版本

搜索示例

让我们将一个典型的搜索请求直接编写为dict:

from elasticsearch import Elasticsearch
client = Elasticsearch()

response = client.search(
    index="my-index",
    body={
      "query": {
        "filtered": {
          "query": {
            "bool": {
              "must": [{"match": {"title": "python"}}],
              "must_not": [{"match": {"description": "beta"}}]
            }
          },
          "filter": {"term": {"category": "search"}}
        }
      },
      "aggs" : {
        "per_tag": {
          "terms": {"field": "tags"},
          "aggs": {
            "max_lines": {"max": {"field": "lines"}}
          }
        }
      }
    }
)

for hit in response['hits']['hits']:
    print(hit['_score'], hit['_source']['title'])

for tag in response['aggregations']['per_tag']['buckets']:
    print(tag['key'], tag['max_lines']['value'])

这种方法的问题在于它非常冗长,容易使用语法 错误,如不正确的嵌套,很难修改(例如,再加一个过滤)和 写起来绝对不好玩。

让我们使用Python DSL重写该示例:

from elasticsearch import Elasticsearch
from elasticsearch_dsl import Search

client = Elasticsearch()

s = Search(using=client, index="my-index") \
    .filter("term", category="search") \
    .query("match", title="python")   \
    .exclude("match", description="beta")

s.aggs.bucket('per_tag', 'terms', field='tags') \
    .metric('max_lines', 'max', field='lines')

response = s.execute()

for hit in response:
    print(hit.meta.score, hit.title)

for tag in response.aggregations.per_tag.buckets:
    print(tag.key, tag.max_lines.value)

如你所见,库负责:

  • 创建适当的Query按名称列出的对象(等式“匹配”)

  • 将查询合成到复合中bool查询

  • 创建filtered查询自.filter()是用来

  • 提供对响应数据的便捷访问

  • 到处都没有花括号或方括号

持久性示例

让我们有一个简单的Python类来表示博客系统中的一篇文章:

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

# Define a default Elasticsearch client
connections.create_connection(hosts=['localhost'])

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

您可以在持久化 chapter.

按查询更新示例

让我们继续以博客上的文章为例,假设每篇文章都有一些赞。 在本例中,假设我们想要将与某个标签匹配但与某个描述不匹配的所有文章的点赞数加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,您可以通过创建一个Search对象从您的 现有dict,使用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()

许可

版权2013弹性研究

按照阿帕奇许可证2.0版(“许可证”)获得许可; 除非遵守许可证,否则您不能使用此文件。 您可以在以下地址获取许可证副本

除非适用法律要求或书面同意,软件 在许可证下分发的是在“按原样”的基础上分发的, 没有任何明示或默示的保证或条件。 请参阅管理权限的特定语言的许可证和 许可证下的限制。