Elasticsearch DSL Python 库 Search DSL 详解

Elasticsearch DSL Python 库 Search DSL 详解

elasticsearch-dsl-py High level Python client for Elasticsearch elasticsearch-dsl-py 项目地址: https://gitcode.com/gh_mirrors/el/elasticsearch-dsl-py

概述

Elasticsearch DSL Python 库是一个高级的 Elasticsearch 客户端,它提供了更 Pythonic 的方式来构建和执行 Elasticsearch 查询。本文将深入探讨该库中的 Search DSL 功能,帮助开发者更好地理解和使用这个强大的工具。

Search 对象

Search 对象是整个搜索请求的核心表示,它封装了以下功能:

  • 查询(queries)
  • 过滤器(filters)
  • 聚合(aggregations)
  • k近邻搜索(k-nearest neighbor searches)
  • 排序(sort)
  • 分页(pagination)
  • 高亮(highlighting)
  • 建议(suggestions)
  • 折叠(collapsing)
  • 额外参数
  • 关联的客户端

设计特点

Search 对象的设计采用了链式调用(chainable)模式,除了聚合功能外,Search 对象是不可变的(immutable)。这意味着任何修改都会创建一个包含变更的浅拷贝,从而可以安全地将 Search 对象传递给外部代码而不用担心被意外修改。

基本使用

首先需要创建一个 Search 对象并关联 Elasticsearch 客户端:

from elasticsearch import Elasticsearch
from elasticsearch_dsl import Search

client = Elasticsearch()
s = Search(using=client)

或者稍后指定客户端:

s = s.using(client)

链式调用示例:

s = Search().using(client).query("match", title="python")

执行查询:

response = s.execute()

迭代结果:

for hit in s:
    print(hit.title)

删除查询匹配的文档

可以通过调用 delete() 方法删除匹配查询的文档:

s = Search(index='i').query("match", title="python")
response = s.delete()

查询(Queries)

查询类型

该库为所有 Elasticsearch 查询类型提供了对应的类:

from elasticsearch_dsl.query import MultiMatch, Match

# 等价于 {"multi_match": {"query": "python django", "fields": ["title", "body"]}}
MultiMatch(query='python django', fields=['title', 'body'])

# 等价于 {"match": {"title": {"query": "web framework", "type": "phrase"}}}
Match(title={"query": "web framework", "type": "phrase"})

Q 快捷方式

使用 Q 快捷方式构造查询:

from elasticsearch_dsl import Q

Q("multi_match", query='python django', fields=['title', 'body'])
Q({"multi_match": {"query": "python django", "fields": ["title", "body"]}})

添加到 Search 对象:

q = Q("multi_match", query='python django', fields=['title', 'body'])
s = s.query(q)

点号字段表示

处理嵌套字段或多字段时,可以使用双下划线 __ 代替点号:

s = Search()
s = s.filter('term', category__keyword='Python')
s = s.query('match', address__city='prague')

或者使用字典解包:

s = Search()
s = s.filter('term', **{'category.keyword': 'Python'})
s = s.query('match', **{'address.city': 'prague'})

查询组合

查询对象可以通过逻辑运算符组合:

# OR 组合
Q("match", title='python') | Q("match", title='django')

# AND 组合
Q("match", title='python') & Q("match", title='django')

# NOT 组合
~Q("match", title="python")

多次调用 .query() 方法会使用 & 运算符内部组合查询。

过滤器(Filters)

过滤上下文

使用 filter() 方法将查询放入过滤上下文:

s = Search()
s = s.filter('terms', tags=['search', 'python'])

等价于:

s = Search()
s = s.query('bool', filter=[Q('terms', tags=['search', 'python'])])

排除查询

使用 exclude() 方法排除匹配项:

s = Search()
s = s.exclude('terms', tags=['search', 'python'])

聚合(Aggregations)

聚合定义

使用 A 快捷方式定义聚合:

from elasticsearch_dsl import A

A('terms', field='tags')  # {"terms": {"field": "tags"}}

嵌套聚合

使用 .bucket(), .metric().pipeline() 方法嵌套聚合:

a = A('terms', field='category')
a.metric('clicks_per_category', 'sum', field='clicks')\
    .bucket('tags_per_category', 'terms', field='tags')

添加到 Search 对象

使用 .aggs 属性添加聚合:

s = Search()
a = A('terms', field='category')
s.aggs.bucket('category_terms', a)

k近邻搜索(K-Nearest Neighbor Searches)

使用 .knn() 方法进行 kNN 搜索:

s = Search()
vector = get_embedding("search text")

s = s.knn(
    field="embedding",
    k=5,
    num_candidates=10,
    query_vector=vector
)

排序(Sorting)

使用 .sort() 方法指定排序:

s = Search().sort(
    'category',  # 升序
    '-title',    # 降序
    {"lines": {"order": "asc", "mode": "avg"}}  # 复杂排序
)

重置排序:

s = s.sort()  # 清除所有排序

分页(Pagination)

使用 Python 切片语法进行分页:

s = s[10:20]  # {"from": 10, "size": 10}
s = s[:20]    # {"size": 20}
s = s[10:]    # {"from": 10}

获取所有匹配文档(不排序):

for hit in s.scan():
    print(hit.title)

高亮(Highlighting)

设置高亮选项:

s = s.highlight_options(order='score')

为字段启用高亮:

s = s.highlight('title')
# 或带参数
s = s.highlight('title', fragment_size=50)

访问高亮片段:

response = s.execute()
for hit in response:
    for fragment in hit.meta.highlight.title:
        print(fragment)

建议(Suggestions)

使用 .suggest() 方法添加建议请求:

# 检查拼写
s = s.suggest('my_suggestion', 'pyhton', term={'field': 'title'})

折叠(Collapsing)

使用 .collapse() 方法折叠搜索结果:

s = Search().query("match", message="GET /search")
s = s.collapse("user_id")  # 按 user_id 折叠结果

展开折叠结果:

inner_hits = {"name": "recent_search", "size": 5, "sort": [{"@timestamp": "desc"}]}
s = s.collapse("user_id", inner_hits=inner_hits, max_concurrent_group_searches=4)

更多功能

额外属性和参数

使用 .extra() 方法设置额外属性:

s = s.extra(explain=True)

使用 .params() 方法设置查询参数:

s = s.params(routing="42")

限制返回字段:

s = s.source(['title', 'body'])  # 只返回指定字段
s = s.source(False)              # 不返回字段,只返回元数据
s = s.source(includes=["title"], excludes=["user.*"])  # 显式包含/排除
s = s.source(None)               # 重置字段选择

序列化和反序列化

将 Search 对象序列化为字典:

s.to_dict()

从字典创建 Search 对象:

s = Search.from_dict({"query": {"match": {"title": "python"}}})

更新现有 Search 对象:

s = Search(index='i')
s.update_from_dict({"query": {"match": {"title": "python"}}, "size": 42})

响应(Response)

执行查询后返回的 Response 对象提供了便捷的访问方式:

response = s.execute()

print(response.success())  # 是否成功
print(response.took)       # 耗时
print(response.hits.total.value)  # 总命中数
print(response.suggest.my_suggestions)  # 建议结果

访问命中结果

response = s.execute()
print('Total %d hits found.' % response.hits.total)
for h in response:
    print(h.title, h.body)

访问结果元数据

h = response.hits[0]
print('/%s/%s/%s returned with score %f' % (
    h.meta.index, h.meta.doc_type, h.meta.id, h.meta.score))

访问聚合结果

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

MultiSearch

使用 MultiSearch 类可以同时执行多个搜索:

from elasticsearch_dsl import MultiSearch, Search

ms = MultiSearch(index='blogs')
ms = ms.add(Search().filter('term', tags='python'))
ms = ms.add(Search().filter('term', tags='elasticsearch'))

responses = ms.execute()

for response in responses:
    print("Results for query %r." % response._search.query)
    for hit in response:
        print(hit.title)

EmptySearch

EmptySearch 是一个特殊版本的 Search,无论查询如何都会返回空结果:

from elasticsearch_dsl import EmptySearch

es = EmptySearch()
response = es.execute()  # 总是返回空结果

总结

Elasticsearch DSL Python 库的 Search DSL 提供了强大而灵活的方式来构建和执行 Elasticsearch 查询。通过本文的介绍,你应该已经掌握了如何使用这个库来构建复杂的查询、聚合和分析请求。记住,这个库的核心设计理念是提供 Pythonic 的接口,同时保持与原生 Elasticsearch API 的紧密对应关系。

elasticsearch-dsl-py High level Python client for Elasticsearch elasticsearch-dsl-py 项目地址: https://gitcode.com/gh_mirrors/el/elasticsearch-dsl-py

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

童霆腾Sorrowful

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值