Python SQL Query Engine
Project description
Query your data, where it lives.
Opteryx is an in-process SQL query engine for analysis of distributed datasets.
Documentation | Examples | Contributing
What is Opteryx?
Opteryx is a Python library designed for data wrangling and analytics. It combines the benefits of in-process database engines like SQLite and DuckDB with query federators like Presto and Trino, providing a flexible and intuitive solution that allows users to seamlessly access and query data from various sources in a unified manner.
Opteryx offers the following features:
- SQL queries on data files generated by other processes such as logs
- A command-line tool for filtering, transforming, and combining files
- Integration with familiar tools like pandas and Polars
- Embeddable as a low-cost engine, enabling portability and allowing for hundreds of analysts to leverage ad hoc databases with ease
- Unified and federated access to data on disk, in the cloud, and in on-premises databases, not only through the same interface but in the same query.
Why Use Opteryx?
Familiar Interface
Opteryx supports key parts of the Python DBAPI and SQL92 standard standards which many analysts and engineers will already know how to use.
Consistent Syntax
Opteryx creates a common SQL-layer over multiple data platforms, allowing backend systems to be upgraded, migrated or consolidated without changing any Opteryx code.
Bring your own Data
Opteryx supports multiple query engines, dataframe APIs and storage formats. You can mix-and-match sources in a single query. Opteryx can even JOIN
datasets stored in different formats, such as Parquet and MySQL.
Opteryx allows you to query your data directly in the systems where they are stored, eliminating the need to duplicate data into a common store for analytics. This saves you the cost and effort of maintaining duplicates.
Opteryx can push parts of your query to the source query engine, allowing queries to run at the speed of the backend, rather than your local computer.
And if there's not a connector in the box for your data platform; bespoke connectors can be added.
Consumption-Based Billing Friendly
Opteryx is well-suited for deployments to environments which are pay-as-you-use, like Google Cloud Run. Great for situations where you have low-volume usage, or multiple environments, where the costs of many traditional database deployment can quickly add up.
Python Native
Opteryx is Open Source Python, it quickly and easily integrates into Python code, including Jupyter Notebooks, so you can start querying your data within a few minutes. You can use Opteryx to run SQL against pandas DataFrames, and even execute a JOIN
on an in-memory DataFrame and a remote dataset.
Time Travel
Designed for data analytics in environments where decisions need to be replayable, Opteryx allows you to query data as at a point in time in the past to replay decision algorithms against facts as they were known in the past. You can even self-join tables historic data, great for finding deltas in datasets over time. (data must be structured to enable temporal queries)
Fast
Benchmarks on M1 Pro Mac running an ad hoc GROUP BY
over a 1Gb parquet file via the CLI in ~1/5th of a second, from a cold start. (different systems will have different performance characteristics)
Rows | Columns | File Size | Query Time |
---|---|---|---|
561225 | 81 | 1Gb | 0.22sec |
1064539 | 81 | 2Gb | 0.27sec |
Instant Elasticity
Designed to run in Knative and similar environments like Google Cloud Run, Opteryx can scale down to zero, and scale up to respond to thousands of concurrent queries within seconds.
Examples
Install from PyPI
Filter a Dataset on the Command Line
Execute a Simple Query in Python
Execute SQL on a pandas DataFrame
Query Data on Local Disk
Query Data on GCS
Query Data in SQLite
Further Examples
Install from PyPI
pip install opteryx
Filter a Dataset on the Command Line
In this example, we are running Opteryx from the command line to filter one of the internal example datasets and display the results on the console.
python -m opteryx "SELECT * FROM \$astronauts WHERE 'Apollo 11' IN UNNEST(missions);"
this example is complete and should run as-is
Execute a Simple Query in Python
In this example, we are showing the basic usage of the Python API by executing a simple query that makes no references to any datasets.
import opteryx
result = opteryx.query("SELECT 4 * 7;")
result.head()
| 4.0*7.0
===#=========
0 | 28.0
this example is complete and should run as-is
Execute SQL on a pandas DataFrame
In this example, we are running a SQL statement on a pandas DataFrame and returning the result as a new pandas DataFrame.
import opteryx
import pandas
pandas_df = pandas.read_csv("https://storage.googleapis.com/opteryx/exoplanets/exoplanets.csv")
opteryx.register_df("exoplanets", pandas_df)
aggregated_df = opteryx.query("SELECT koi_disposition, COUNT(*) FROM exoplanets GROUP BY koi_disposition;").pandas()
aggregated_df.head()
koi_disposition COUNT(*)
0 CONFIRMED 2293
1 FALSE POSITIVE 5023
2 CANDIDATE 2248
this example is complete and should run as-is
Query Data on Local Disk
In this example, we are querying and filtering a file directly. This example will not run as written because the file being queried does not exist.
import opteryx
result = opteryx.query("SELECT * FROM 'space_missions.parquet' LIMIT 5;")
result.head()
| Company | Location | Price | Launched_at | Rocket | Rocket_Status | Mission | Mission_Status
=====#===========#================================#=======#=====================#================#===============#================#================
0 | RVSN USSR | Site 1/5, Baikonur Cosmodrome, | None | 1957-10-04 19:28:00 | Sputnik 8K71PS | Retired | Sputnik-1 | Success
1 | RVSN USSR | Site 1/5, Baikonur Cosmodrome, | None | 1957-11-03 02:30:00 | Sputnik 8K71PS | Retired | Sputnik-2 | Success
2 | US Navy | LC-18A, Cape Canaveral AFS, Fl | None | 1957-12-06 16:44:00 | Vanguard | Retired | Vanguard TV3 | Failure
3 | AMBA | LC-26A, Cape Canaveral AFS, Fl | None | 1958-02-01 03:48:00 | Juno I | Retired | Explorer 1 | Success
4 | US Navy | LC-18A, Cape Canaveral AFS, Fl | None | 1958-02-05 07:33:00 | Vanguard | Retired | Vanguard TV3BU | Failure
this example requires a data file, space_missions.parquet.
Query Data in SQLite
In this example, we are querying a SQLite database via Opteryx. This example will not run as written because the file being queried does not exist.
import opteryx
from opteryx.connectors import SqlConnector
# Register the store, so we know queries for the 'sql' store should be handled by
# the SQL Connector
opteryx.register_store(
prefix="sql",
connector=SqlConnector,
remove_prefix=True, # the prefix isn't part of the SQLite table name
connection="sqlite:///database.db" # SQLAlchemy connection string
)
result = opteryx.query("SELECT name, mass, diameter, density FROM sql.planets LIMIT 5;")
result.head()
│ name │ mass │ diameter │ density
═══#═════════#════════#══════════#════════
0 │ Mercury │ 0.33 │ 4879.0 │ 5427.0
1 │ Venus │ 4.87 │ 12104.0 │ 5243.0
2 │ Earth │ 5.97 │ 12756.0 │ 5514.0
3 │ Mars │ 0.642 │ 6792.0 │ 3933.0
4 │ Jupiter │ 1898.0 │ 142984.0 │ 1326.0
this example requires a data file, database.db.
Query Data on GCS
In this example, we are to querying a dataset on GCS in a public bucket called 'opteryx'.
import opteryx
from opteryx.connectors import GcpCloudStorageConnector
# Register the store, so we know queries for this store should be handled by
# the GCS connector
opteryx.register_store("opteryx", GcpCloudStorageConnector)
result = opteryx.query("SELECT * FROM opteryx.space_missions LIMIT 5;")
result.head()
| Company | Location | Price | Launched_at | Rocket | Rocket_Status | Mission | Mission_Status
=====#===========#================================#=======#=====================#================#===============#================#================
0 | RVSN USSR | Site 1/5, Baikonur Cosmodrome, | None | 1957-10-04 19:28:00 | Sputnik 8K71PS | Retired | Sputnik-1 | Success
1 | RVSN USSR | Site 1/5, Baikonur Cosmodrome, | None | 1957-11-03 02:30:00 | Sputnik 8K71PS | Retired | Sputnik-2 | Success
2 | US Navy | LC-18A, Cape Canaveral AFS, Fl | None | 1957-12-06 16:44:00 | Vanguard | Retired | Vanguard TV3 | Failure
3 | AMBA | LC-26A, Cape Canaveral AFS, Fl | None | 1958-02-01 03:48:00 | Juno I | Retired | Explorer 1 | Success
4 | US Navy | LC-18A, Cape Canaveral AFS, Fl | None | 1958-02-05 07:33:00 | Vanguard | Retired | Vanguard TV3BU | Failure
this example is complete and should run as-is
Further Examples
For prepared example usage, see the below Notebooks on Google Colab.
Community
How do I get Support?
For support ask our Gitter Community.
How Can I Contribute?
We are looking for volunteers to help build and direct Opteryx. If you are interested please use the Issues to let use know.
All contributions, bug reports, documentation improvements, enhancements, and ideas are welcome.
Want to help build Opteryx? See the Contribution and Set Up Guides.
Security
See the project Security Policy for information about reporting vulnerabilities.
License
Opteryx is licensed under Apache 2.0 unless otherwise noted.
Status
Opteryx is in beta. Beta means different things to different people, to us, being beta means:
- Core functionality has good regression test coverage to help ensure stability
- Some edge cases may have undetected bugs
- Performance tuning is incomplete
- Changes are focused on feature completion, bugs, performance, reducing debt, and security
- Code structure and APIs are not stable and may change
Related Projects
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Hashes for opteryx-0.11.0-cp311-cp311-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | b0fad4af4793d6b6a63b9fc49f8b3ebb3e38bf23f9eca783a4ab130220272476 |
|
MD5 | b69d2f65a1309a0f5aacb6bd164fc3bf |
|
BLAKE2b-256 | 8cc0c7bf54f8f47ccf01a7b6d48ba21d1f1dcd592d55b817249751c619c0c3c8 |
Hashes for opteryx-0.11.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 43b35471dd6cf3793aab0feb3cd630441cbd83033d3a10dceffbf03f16bae9c0 |
|
MD5 | 9f04f6cbe115bee69c573dcbf031672f |
|
BLAKE2b-256 | c85ab8961506a7751893a21b96631f501e11e7ec2e97fbbb00bfc8366374fa4f |
Hashes for opteryx-0.11.0-cp311-cp311-macosx_10_15_universal2.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | bf5e87c3be3f54f32fc4daaed49d890a670d2af61a50c2ed8545676c288e25e3 |
|
MD5 | 3bbe214dd3bcafdc9959221fe68df9db |
|
BLAKE2b-256 | 28283a75a42725fd91cee44ab848ceb7cf70f39983e5ef546cfab1b66cb0446d |
Hashes for opteryx-0.11.0-cp310-cp310-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 243b3d4617267c937ee179254693885e46c1305a634f19c0fcf25716c075c797 |
|
MD5 | 63213af428c26cbfd89f7c4acd266326 |
|
BLAKE2b-256 | b5db7f731f3e84da3dd77207c2edd55353eacfe970bb68f0155020fc641b96eb |
Hashes for opteryx-0.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 9aa95aa3187d55ba2242a3e6b2cfcea5a593ed8aaf439f24dae35fa541a07aca |
|
MD5 | bcb19a8446270bce02032116c79a1a18 |
|
BLAKE2b-256 | 53c9d314fdf3d27f064f7dc6bb0fbb59dcca43f13044c3d52a68be4895498e56 |
Hashes for opteryx-0.11.0-cp310-cp310-macosx_10_15_universal2.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 3b2a9b0325ef0c105d7fd85ee268c8096603d0c8f38381de04bb035893e96a3f |
|
MD5 | 039eaf3c3531b209d285af586487b750 |
|
BLAKE2b-256 | 5e25d123d48b4d94795c45b6c7c565b1182db182359afe681b5160eb7c2595e3 |
Hashes for opteryx-0.11.0-cp39-cp39-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 01f875098329184e7ff0092b7045e9377ccdc6ac94280e052f6b54a5145568a7 |
|
MD5 | 44fe3e55ecaf61ecbc396219bd43e63a |
|
BLAKE2b-256 | 362996facecf6b6db38fd3838c0fb60d5ff222493e6319ba4e7460ff0c90c62f |
Hashes for opteryx-0.11.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 418786d826f331a5687310c020d9c71ea44d649231ba7f16890c8bf49c74f434 |
|
MD5 | a5e807748c1790b369b3f9b0898a129e |
|
BLAKE2b-256 | 9a139ac8105cc70049aa2f6d33cee919d2c48fba95c1b3c44c5a65a5462d820d |
Hashes for opteryx-0.11.0-cp39-cp39-macosx_10_15_universal2.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | d6febd93872ef2f23b67e08766bf7bc858bdfa91d6babafea9f1a33070f531b4 |
|
MD5 | cea957af0e375c6e09260b7edd7c655c |
|
BLAKE2b-256 | 03c27859f5e90a04871735e4d9e8f80d6e83fd19530d241195f0b73b8c8118f9 |
Hashes for opteryx-0.11.0-cp38-cp38-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | b9b89772698cbe53194e57395116d037f9ade24fdc4a47c38265c60d6d9bcbaa |
|
MD5 | 4280cb3f1577f4f0346fadb2cb8f5e3f |
|
BLAKE2b-256 | c212109b865cb3549b22ae55f282225446d71d4a89d521a3d63f03bcc076a3a5 |
Hashes for opteryx-0.11.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | a9abe4d29dd4166bf5ee4c4360f77b20585043c06bfe3168f84744d75e1d8b3b |
|
MD5 | f56ab1731d32b06616a7d2ae76b46007 |
|
BLAKE2b-256 | 488fbffaf9ca33d7fa75c7f2540e1d3201fd95dbbc21e9d094e31812feec2626 |
Hashes for opteryx-0.11.0-cp38-cp38-macosx_10_15_universal2.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 88b76001a12ccfdc6d12550712630ce7b68d5d0ec3c5d802b38836d5f1e6500a |
|
MD5 | 2b00bfa4e2b8ed7af7db7716b0a78609 |
|
BLAKE2b-256 | 3b2b5cc8f3c59bc4e70ba5d976cc7f3178b2df07cd81969d7ad68d265b41ad94 |