Elasticsearch DSL — это библиотека высокого уровня, цель которой — помочь в написании и выполнении запросов к Elasticsearch. Он построен на основе официального низкоуровневого клиента (elasticsearch-py).
Он обеспечивает более удобный и идиоматический способ написания запросов и управления ими. Он близок к Elasticsearch JSON DSL, отражая его терминологию и структуру. Он предоставляет весь диапазон DSL из Python либо напрямую, используя определенные классы, либо выражения, подобные набору запросов.
Он также предоставляет дополнительную оболочку для работы с документами как объектами Python: определение сопоставлений, получение и сохранение документов, упаковка данных документа в определяемые пользователем классы.
Чтобы использовать другие API Elasticsearch (например, работоспособность кластера), просто используйте базовый клиент.
pip установить elasticsearch-dsl
Пожалуйста, посетите каталог примеров, чтобы увидеть некоторые сложные примеры использования elasticsearch-dsl
.
Библиотека совместима со всеми версиями Elasticsearch, начиная с 2.x
, но вам необходимо использовать соответствующую основную версию :
Для Elasticsearch 8.0 и более поздних версий используйте основную версию библиотеки 8 ( 8.xy
).
Для Elasticsearch 7.0 и более поздних версий используйте основную версию библиотеки 7 ( 7.xy
).
Для Elasticsearch 6.0 и более поздних версий используйте основную версию библиотеки 6 ( 6.xy
).
Для Elasticsearch 5.0 и более поздних версий используйте основную версию библиотеки 5 ( 5.xy
).
Для Elasticsearch 2.0 и более поздних версий используйте основную версию библиотеки 2 ( 2.xy
).
Рекомендуемый способ установки требований в файле setup.py или require.txt:
# Elasticsearch 8.x elasticsearch-dsl>=8.0.0,<9.0.0 # 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
Разработка ведется на main
, в более старых ветках выпускаются только исправления ошибок.
Давайте возьмем типичный поисковый запрос, записанный непосредственно в виде dict
:
from elasticsearch import Elasticsearch
client = Elasticsearch ( "https://localhost:9200" )
response = client . search (
index = "my-index" ,
body = {
"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 ( "https://localhost:9200" )
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
запросterm
запроса в контекст фильтра bool
-запросаДавайте создадим простой класс 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-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 ()
Активируйте виртуальную среду (virtualenvs):
$ virtualenv venv
$ source venv/bin/activate
Чтобы установить все зависимости, необходимые для разработки, запустите:
$ pip install -e ' .[develop] '
Чтобы запустить все тесты elasticsearch-dsl-py
, запустите:
$ python setup.py test
В качестве альтернативы можно использовать сценарий run_tests.py
в test_elasticsearch_dsl
, который является оболочкой pytest, для запуска подмножеств набора тестов. Некоторые примеры можно увидеть ниже:
# Run all of the tests in `test_elasticsearch_dsl/test_analysis.py`
$ ./run_tests.py test_analysis.py
# Run only the `test_analyzer_serializes_as_name` test.
$ ./run_tests.py test_analysis.py::test_analyzer_serializes_as_name
pytest
будет пропускать тесты из test_elasticsearch_dsl/test_integration
, если не существует экземпляра Elasticsearch, на котором может возникнуть соединение. По умолчанию тестовое подключение осуществляется по адресу localhost:9200
на основе значений по умолчанию, указанных в классе подключения elasticsearch-py
. Поскольку запуск интеграционных тестов приведет к деструктивным изменениям в кластере Elasticsearch, запускайте их только тогда, когда связанный кластер пуст. Таким образом, если экземпляр Elasticsearch по адресу localhost:9200
не соответствует этим требованиям, можно указать другой тестовый сервер Elasticsearch через переменную среды TEST_ES_SERVER
.
$ TEST_ES_SERVER=my-test-server:9201 ./run_tests
Документация доступна по адресу https://elasticsearch-dsl.readthedocs.io.
Хотите взломать Elasticsearch DSL? Потрясающий! У нас есть Contribution-Guide.
© Elasticsearch, 2013 г.
Лицензируется по лицензии Apache версии 2.0 («Лицензия»); вы не можете использовать этот файл, кроме как в соответствии с Лицензией. Вы можете получить копию Лицензии по адресу
http://www.apache.org/licenses/LICENSE-2.0
Если это не требуется действующим законодательством или не согласовано в письменной форме, программное обеспечение, распространяемое по Лицензии, распространяется на условиях «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ ИЛИ УСЛОВИЙ, явных или подразумеваемых. См. Лицензию для определения конкретного языка, регулирующего разрешения и ограничения в рамках Лицензии.