Graphene Elasticsearch/OpenSearch (DSL)集成
项目描述
Elasticsearch (DSL)/ OpenSearch (DSL)集成,用于Graphene。
先决条件
Graphene 2.x。 不打算支持Graphene 1.x。
Python 3.6, 3.7, 3.8, 3.9和3.10。 不打算支持Python 2。
Elasticsearch 6.x, 7.x。 不打算支持Elasticsearch 5.x。
OpenSearch 1.x, 2.x。
主要功能和亮点
实现了ElasticsearchConnectionField和ElasticsearchObjectType,它们是处理graphene的核心类。
可插拔的后端用于搜索、过滤、排序等。不喜欢现有的?重写、扩展或编写自己的。
搜索后端。
过滤后端。
排序后端。
分页。
高亮后端。
源过滤后端。
分面搜索后端(包括全局聚合)。
后过滤后端。
分数过滤后端。
查询字符串后端。
简单的查询字符串后端。
查看路线图了解尚未实施的功能。
您需要Django REST Framework的类似工具吗?请查看django-elasticsearch-dsl-drf。
演示
查看实时演示应用程序(FastAPI + Graphene 2 + Elasticsearch 7),该应用程序托管在Heroku和bonsai.io。
文档
文档可在Read the Docs上找到。
安装
从PyPI安装最新稳定版本
pip install graphene-elastic
或从GitHub安装最新开发版本
pip install https://github.com/barseghyanartur/graphene-elastic/archive/master.zip
示例
安装需求
pip install -r requirements.txt
填充示例数据
以下命令将为User和Post文档创建索引,并用示例数据填充它们
./scripts/populate_elasticsearch_data.sh
示例文档定义
search_index/documents/post.py
查看examples/search_index/documents/post.py的完整示例。
import datetime
from elasticsearch_dsl import (
Boolean,
Date,
Document,
InnerDoc,
Keyword,
Nested,
Text,
Integer,
)
class Comment(InnerDoc):
author = Text(fields={'raw': Keyword()})
content = Text(analyzer='snowball')
created_at = Date()
def age(self):
return datetime.datetime.now() - self.created_at
class Post(Document):
title = Text(
fields={'raw': Keyword()}
)
content = Text()
created_at = Date()
published = Boolean()
category = Text(
fields={'raw': Keyword()}
)
comments = Nested(Comment)
tags = Text(
analyzer=html_strip,
fields={'raw': Keyword(multi=True)},
multi=True
)
num_views = Integer()
class Index:
name = 'blog_post'
settings = {
'number_of_shards': 1,
'number_of_replicas': 1,
'blocks': {'read_only_allow_delete': None},
}
示例应用程序
示例Flask应用程序
运行示例Flask应用程序
./scripts/run_flask.sh
打开Flask graphiql客户端
http://127.0.0.1:8001/graphql
示例Django应用程序
运行示例Django应用程序
./scripts/run_django.sh runserver
打开Django graphiql客户端
http://127.0.0.1:8000/graphql
连接字段示例
连接字段是您拥有的最灵活且功能丰富的解决方案。它使用筛选后端,您可以以声明性的方式根据需要将其绑定到您的需求。
示例模式定义
import graphene
from graphene_elastic import (
ElasticsearchObjectType,
ElasticsearchConnectionField,
)
from graphene_elastic.filter_backends import (
FilteringFilterBackend,
SearchFilterBackend,
HighlightFilterBackend,
OrderingFilterBackend,
DefaultOrderingFilterBackend,
)
from graphene_elastic.constants import (
LOOKUP_FILTER_PREFIX,
LOOKUP_FILTER_TERM,
LOOKUP_FILTER_TERMS,
LOOKUP_FILTER_WILDCARD,
LOOKUP_QUERY_EXCLUDE,
LOOKUP_QUERY_IN,
)
# Object type definition
class Post(ElasticsearchObjectType):
class Meta(object):
document = PostDocument
interfaces = (Node,)
filter_backends = [
FilteringFilterBackend,
SearchFilterBackend,
HighlightFilterBackend,
OrderingFilterBackend,
DefaultOrderingFilterBackend,
]
# For `FilteringFilterBackend` backend
filter_fields = {
# The dictionary key (in this case `title`) is the name of
# the corresponding GraphQL query argument. The dictionary
# value could be simple or complex structure (in this case
# complex). The `field` key points to the `title.raw`, which
# is the field name in the Elasticsearch document
# (`PostDocument`). Since `lookups` key is provided, number
# of lookups is limited to the given set, while term is the
# default lookup (as specified in `default_lookup`).
'title': {
'field': 'title.raw',
# Available lookups
'lookups': [
LOOKUP_FILTER_TERM,
LOOKUP_FILTER_TERMS,
LOOKUP_FILTER_PREFIX,
LOOKUP_FILTER_WILDCARD,
LOOKUP_QUERY_IN,
LOOKUP_QUERY_EXCLUDE,
],
# Default lookup
'default_lookup': LOOKUP_FILTER_TERM,
},
# The dictionary key (in this case `category`) is the name of
# the corresponding GraphQL query argument. Since no lookups
# or default_lookup is provided, defaults are used (all lookups
# available, term is the default lookup). The dictionary value
# (in this case `category.raw`) is the field name in the
# Elasticsearch document (`PostDocument`).
'category': 'category.raw',
# The dictionary key (in this case `tags`) is the name of
# the corresponding GraphQL query argument. Since no lookups
# or default_lookup is provided, defaults are used (all lookups
# available, term is the default lookup). The dictionary value
# (in this case `tags.raw`) is the field name in the
# Elasticsearch document (`PostDocument`).
'tags': 'tags.raw',
# The dictionary key (in this case `num_views`) is the name of
# the corresponding GraphQL query argument. Since no lookups
# or default_lookup is provided, defaults are used (all lookups
# available, term is the default lookup). The dictionary value
# (in this case `num_views`) is the field name in the
# Elasticsearch document (`PostDocument`).
'num_views': 'num_views',
}
# For `SearchFilterBackend` backend
search_fields = {
'title': {'boost': 4},
'content': {'boost': 2},
'category': None,
}
# For `OrderingFilterBackend` backend
ordering_fields = {
# The dictionary key (in this case `tags`) is the name of
# the corresponding GraphQL query argument. The dictionary
# value (in this case `tags.raw`) is the field name in the
# Elasticsearch document (`PostDocument`).
'title': 'title.raw',
# The dictionary key (in this case `created_at`) is the name of
# the corresponding GraphQL query argument. The dictionary
# value (in this case `created_at`) is the field name in the
# Elasticsearch document (`PostDocument`).
'created_at': 'created_at',
# The dictionary key (in this case `num_views`) is the name of
# the corresponding GraphQL query argument. The dictionary
# value (in this case `num_views`) is the field name in the
# Elasticsearch document (`PostDocument`).
'num_views': 'num_views',
}
# For `DefaultOrderingFilterBackend` backend
ordering_defaults = (
'-num_views', # Field name in the Elasticsearch document
'title.raw', # Field name in the Elasticsearch document
)
# For `HighlightFilterBackend` backend
highlight_fields = {
'title': {
'enabled': True,
'options': {
'pre_tags': ["<b>"],
'post_tags': ["</b>"],
}
},
'content': {
'options': {
'fragment_size': 50,
'number_of_fragments': 3
}
},
'category': {},
}
# Query definition
class Query(graphene.ObjectType):
all_post_documents = ElasticsearchConnectionField(Post)
# Schema definition
schema = graphene.Schema(query=Query)
筛选器
示例查询
由于我们没有在category上指定任何查找,因此默认所有查找都可用,默认查找将是term。注意,在{value:"Elastic"}部分,value表示默认查找,无论其设置为多少。
query PostsQuery {
allPostDocuments(filter:{category:{value:"Elastic"}}) {
edges {
node {
id
title
category
content
createdAt
comments
}
}
}
}
但是,我们可以使用另一个查找(以下示例中的terms)。注意,在{terms:["Elastic", "Python"]}部分,terms是查找名称。
query PostsQuery {
allPostDocuments(
filter:{category:{terms:["Elastic", "Python"]}}
) {
edges {
node {
id
title
category
content
createdAt
comments
}
}
}
}
或者,在筛选的同时应用一个gt(范围)查询
{
allPostDocuments(filter:{
category:{term:"Python"},
numViews:{gt:"700"}
}) {
edges {
node {
category
title
comments
numViews
}
}
}
}
实现的筛选查找
以下查找可用
包含
ends_with(或endsWith用于驼峰式命名)
排除
存在
gt
gte
in
is_null(或驼峰式写法的isNull)
lt
lte
prefix
range
starts_with(或驼峰式写法的startsWith)
term
terms
wildcard
有关过滤器查找的更多信息,请参阅专用文档。
搜索
搜索所有字段
query {
allPostDocuments(
search:{query:"Release Box"}
) {
edges {
node {
category
title
content
}
}
}
}
搜索指定字段
query {
allPostDocuments(
search:{
title:{value:"Release", boost:2},
content:{value:"Box"}
}
) {
edges {
node {
category
title
content
}
}
}
}
排序
可能的选项是ASC和DESC。
query {
allPostDocuments(
filter:{category:{term:"Photography"}},
ordering:{title:ASC}
) {
edges {
node {
category
title
content
numViews
tags
}
}
}
}
分页
支持first、last、before和after参数。默认情况下,结果数量限制为100。
query {
allPostDocuments(first:12) {
pageInfo {
startCursor
endCursor
hasNextPage
hasPreviousPage
}
edges {
cursor
node {
category
title
content
numViews
}
}
}
}
高亮显示
只需列出您想要高亮的字段。这仅在结合搜索时才有效。
query {
allPostDocuments(
search:{content:{value:"alice"}, title:{value:"alice"}},
highlight:[category, content]
) {
edges {
node {
title
content
highlight
}
cursor
}
}
}
路线图
路线图和开发计划。
本包是在django-elasticsearch-dsl-drf的基础上设计的,旨在提供类似的功能。
计划在即将推出的Beta版本中发布许多功能
建议器后端。
嵌套后端。
地理空间后端。
过滤器查找geo_bounding_box(或驼峰式写法的geoBoundingBox)。
过滤器查找geo_distance(或驼峰式写法的geoDistance)。
过滤器查找geo_polygon(或驼峰式写法的geoPolygon)。
类似的后端。
请继续关注或联系我,如果您想帮忙。
测试
项目包含测试。
使用Docker进行测试
make docker-test
使用virtualenv或tox运行测试
默认情况下,测试针对Elasticsearch 7.x执行。
使用Docker运行Elasticsearch 7.x
docker-compose up elasticsearch
安装测试需求
pip install -r requirements/test.txt
要测试所有支持的Python版本,请输入
tox
要测试特定环境,请输入
tox -e py38-elastic7
要仅测试您的工作环境,请输入
./runtests.py
要运行您工作环境中的单个测试模块,请输入
./runtests.py src/graphene_elastic/tests/test_filter_backend.py
要运行在给定测试模块中的单个测试类,请输入
./runtests.py src/graphene_elastic/tests/test_filter_backend.py::FilterBackendElasticTestCase
调试
出于开发目的,您可以使用flask应用(易于调试)。标准的pdb也可以工作(import pdb; pdb.set_trace())。如果ipdb对您不起作用,请使用ptpdb。
编写文档
请保持以下层次结构。
=====
title
=====
header
======
sub-header
----------
sub-sub-header
~~~~~~~~~~~~~~
sub-sub-sub-header
^^^^^^^^^^^^^^^^^^
sub-sub-sub-sub-header
++++++++++++++++++++++
sub-sub-sub-sub-sub-header
**************************
许可证
GPL-2.0-only OR LGPL-2.1-or-later
支持
项目详情
下载文件
下载适用于您平台的文件。如果您不确定选择哪个,请了解有关安装包的更多信息。
源分布
构建分发版
graphene-elastic-0.8.1.tar.gz的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 2ee1f8adb5f82a81680172ef8240abc3ea723126f752a5c02efde07cc95c03ce |
|
MD5 | 4b2582b38df5f0b03a087a4b78a7583d |
|
BLAKE2b-256 | 2ec307117aa415f2df22bf5eade1dcbd8c9a95c004715a2efe66122a77fa2fa3 |
graphene_elastic-0.8.1-py2.py3-none-any.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 14209df67ca7812fa150a42d958db530cc8ca42a0e1d9c9ea497b80962bca9c6 |
|
MD5 | 732f925d43cbf860d283f1122c040cf8 |
|
BLAKE2b-256 | b25130c2e56da3bef5e163dfdbdd6e223bd62b4738193e598bde3b8e5746b9ed |