10 Star 54 Fork 4

cozodb / cozo

Create your Gitee Account
Explore and code with more than 12 million developers,Free private repositories !:)
Sign up
Clone or Download
Sync branch
Notice: Creating folder will generate an empty file .keep, because not support in Git

docs cozo-node npm (web) Crates.io docs.rs pypi java clj android pod Go C GitHub Workflow Status GitHub


Table of contents

  1. Introduction
  2. Getting started
  3. Install
  4. Architecture
  5. Status of the project
  6. Links
  7. Licensing and contributing

🎉🎉🎉 New versions 🎉🎉🎉

Version v0.7: after HNSW vector search from 0.6, in 0.7 we bring to you MinHash-LSH for near-duplicate search, full-text search, Json value support and more! See here for more details.

Version v0.6 released! This version brings vector search with HNSW indices inside Datalog, which can be integrated seamlessly with powerful features like ad-hoc joins, recursive Datalog and classical whole-graph algorithms. This significantly expanded the horizon of possibilities of CozoDB.


  • You can now create HNSW (hierarchical navigable small world) indices on relations containing vectors.
  • You can create multiple HNSW indices for the same relation by specifying filters dictating which rows should be indexed, or which vector(s) should be indexed for each row if the row contains multiple vectors.
  • The vector search functionality is integrated within Datalog, meaning that you can use vectors (either explicitly given or coming from another relation) as pivots to perform unification into the indexed relations (roughly equivalent to table joins in SQL).
  • Unification with vector search is semantically no different from regular unification, meaning that you can even use vector search in recursive Datalog, enabling extremely complex query logic.
  • The HNSW index is no more than a hierarchy of proximity graphs. As an open, competent graph database, CozoDB exposes these graphs to the end user to be used as regular graphs in your query, so that all the usual techniques for dealing with them can now be applied, especially: community detection and other classical whole-graph algorithms.
  • As with all mutations in CozoDB, the index is protected from corruption in the face of concurrent writes by using Multi-Version Concurrency Control (MVCC), and you can use multi-statement transactions for complex workflows.
  • The index resides on disk as a regular relation (unless you use the purely in-memory storage option, of course). During querying, close to the absolute minimum amount of memory is used, and memory is freed as soon as the processing is done (thanks to Rust's RAII), so it can run on memory-constrained systems.
  • The HNSW functionality is available for CozoDB on all platforms: in the server as a standalone service, in your Python, NodeJS, or Clojure programs om embedded or client mode, on your phone in embedded mode, even in the browser with the WASM backend.
  • HNSW vector search in CozoDB is performant: we have optimized the index to the point where basic vector operations themselves have become a limiting factor (along with memcpy), and we are constantly finding ways to improve our new implementation of the HNSW algorithm further.

See here for more details.


CozoDB is a general-purpose, transactional, relational database that uses Datalog for query, is embeddable but can also handle huge amounts of data and concurrency, and focuses on graph data and algorithms. It supports time travel and it is performant!

What does embeddable mean here?

A database is almost surely embedded if you can use it on a phone which never connects to any network (this situation is not as unusual as you might think). SQLite is embedded. MySQL/Postgres/Oracle are client-server.

A database is embedded if it runs in the same process as your main program. This is in contradistinction to client-server databases, where your program connects to a database server (maybe running on a separate machine) via a client library. Embedded databases generally require no setup and can be used in a much wider range of environments.

We say CozoDB is embeddable instead of embedded since you can also use it in client-server mode, which can make better use of server resources and allow much more concurrency than in embedded mode.

Why graphs?

Because data are inherently interconnected. Most insights about data can only be obtained if you take this interconnectedness into account.

Most existing graph databases start by requiring you to shoehorn your data into the labelled-property graph model. We don't go this route because we think the traditional relational model is much easier to work with for storing data, much more versatile, and can deal with graph data just fine. Even more importantly, the most piercing insights about data usually come from graph structures implicit several levels deep in your data. The relational model, being an algebra, can deal with it just fine. The property graph model, not so much, since that model is not very composable.

What is so cool about Datalog?

Datalog can express all relational queries. Recursion in Datalog is much easier to express, much more powerful, and usually runs faster than in SQL. Datalog is also extremely composable: you can build your queries piece by piece.

Recursion is especially important for graph queries. CozoDB's dialect of Datalog supercharges it even further by allowing recursion through a safe subset of aggregations, and by providing extremely efficient canned algorithms (such as PageRank) for the kinds of recursions frequently required in graph analysis.

As you learn Datalog, you will discover that the rules of Datalog are like functions in a programming language. Rules are composable, and decomposing a query into rules can make it clearer and more maintainable, with no loss in efficiency. This is unlike the monolithic approach taken by the SQL select-from-where in nested forms, which can sometimes read like golfing.

Time travel?

Time travel in the database setting means tracking changes to data over time and allowing queries to be logically executed at a point in time to get a historical view of the data.

In a sense, this makes your database immutable, since nothing is really deleted from the database ever.

In Cozo, instead of having all data automatically support time travel, we let you decide if you want the capability for each of your relation. Every extra functionality comes with its cost, and you don't want to pay the price if you don't use it.

For the reason why you might want time travel for your data, we have written a short story.

How performant?

On a 2020 Mac Mini with the RocksDB persistent storage engine (CozoDB supports many storage engines):

  • Running OLTP queries for a relation with 1.6M rows, you can expect around 100K QPS (queries per second) for mixed read/write/update transactional queries, and more than 250K QPS for read-only queries, with database peak memory usage around 50MB.
  • Speed for backup is around 1M rows per second, for restore is around 400K rows per second, and is insensitive to relation (table) size.
  • For OLAP queries, it takes around 1 second (within a factor of 2, depending on the exact operations) to scan a table with 1.6M rows. The time a query takes scales roughly with the number of rows the query touches, with memory usage determined mainly by the size of the return set.
  • Two-hop graph traversal completes in less than 1ms for a graph with 1.6M vertices and 31M edges.
  • The Pagerank algorithm completes in around 50ms for a graph with 10K vertices and 120K edges, around 1 second for a graph with 100K vertices and 1.7M edges, and around 30 seconds for a graph with 1.6M vertices and 32M edges.

For more numbers and further details, we have a writeup about performance here.

Getting started

Usually, to learn a database, you need to install it first. This is unnecessary for CozoDB as a testimony to its extreme embeddability, since you can run a complete CozoDB instance in your browser, at near-native speed for most operations!

So open up the CozoDB in WASM page, and then:

Or you can skip ahead for the information about installing CozoDB into your favourite environment first.


If you are in a hurry and just want a taste of what querying with CozoDB is like, here it is. In the following *route is a relation with two columns fr and to, representing a route between those airports, and FRA is the code for Frankfurt Airport.

How many airports are directly connected to FRA?

?[count_unique(to)] := *route{fr: 'FRA', to}

How many airports are reachable from FRA by one stop?

?[count_unique(to)] := *route{fr: 'FRA', to: stop},
                       *route{fr: stop, to}

How many airports are reachable from FRA by any number of stops?

reachable[to] := *route{fr: 'FRA', to}
reachable[to] := reachable[stop], *route{fr: stop, to}
?[count_unique(to)] := reachable[to]

What are the two most difficult-to-reach airports by the minimum number of hops required, starting from FRA?

shortest_paths[to, shortest(path)] := *route{fr: 'FRA', to},
                                      path = ['FRA', to]
shortest_paths[to, shortest(path)] := shortest_paths[stop, prev_path],
                                      *route{fr: stop, to},
                                      path = append(prev_path, to)
?[to, path, p_len] := shortest_paths[to, path], p_len = length(path)

:order -p_len
:limit 2
to path p_len
YPO ["FRA","YYZ","YTS","YMO","YFA","ZKE","YAT","YPO"] 8
BVI ["FRA","AUH","BNE","ISA","BQL","BEU","BVI"] 7

What is the shortest path between FRA and YPO, by actual distance travelled?

start[] <- [['FRA']]
end[] <- [['YPO]]
?[src, dst, distance, path] <~ ShortestPathDijkstra(*route[], start[], end[])
src dst distance path
FRA YPO 4544.0 ["FRA","YUL","YVO","YKQ","YMO","YFA","ZKE","YAT","YPO"]

CozoDB attempts to provide nice error messages when you make mistakes:

?[x, Y] := x = 1, y = x + 1

  × Symbol 'Y' in rule head is unbound
 1 │ ?[x, Y] := x = 1, y = x + 1
  help: Note that symbols occurring only in negated positions are not considered bound


We suggest that you try out CozoDB before you install it in your environment.

How you install CozoDB depends on which environment you want to use it in. Follow the links in the table below:

Language/Environment Official platform support Storage
Python Linux (x86_64), Mac (ARM64, x86_64), Windows (x86_64) MQR
NodeJS Linux (x86_64, ARM64), Mac (ARM64, x86_64), Windows (x86_64) MQR
Web browser Modern browsers supporting web assembly M
Java (JVM) Linux (x86_64, ARM64), Mac (ARM64, x86_64), Windows (x86_64) MQR
Clojure (JVM) Linux (x86_64, ARM64), Mac (ARM64, x86_64), Windows (x86_64) MQR
Android Android (ARM64, ARMv7, x86_64, x86) MQ
iOS/MacOS (Swift) iOS (ARM64, simulators), Mac (ARM64, x86_64) MQ
Rust Source only, usable on any platform with std support MQRST
Golang Linux (x86_64, ARM64), Mac (ARM64, x86_64), Windows (x86_64) MQR
C/C++/language with C FFI Linux (x86_64, ARM64), Mac (ARM64, x86_64), Windows (x86_64) MQR
Standalone HTTP server Linux (x86_64, ARM64), Mac (ARM64, x86_64), Windows (x86_64) MQRST
Lisp Linux (x86_64 so far) MR
Smalltalk Win10 & Linux (Ubuntu 23.04) x86_64 tested, MacOS should probably work MQR

For the storage column:

  • M: in-memory, non-persistent backend
  • Q: SQLite storage backend
  • R: RocksDB storage backend
  • S: Sled storage backend
  • T: TiKV distributed storage backend

The Rust doc has some tips on choosing storage, which is helpful even if you are not using Rust. Even if a storage/platform is not officially supported, you can still try to compile your version to use, maybe with some tweaks in the code.

Tuning the RocksDB backend for CozoDB

RocksDB has a lot of options, and by tuning them you can achieve better performance for your workload. This is probably unnecessary for 95% of users, but if you are the remaining 5%, CozoDB gives you the options to tune RocksDB directly if you are using the RocksDB storage engine.

When you create the CozoDB instance with the RocksDB backend option, you are asked to provide a path to a directory to store the data (will be created if it does not exist). If you put a file named options inside this directory, the engine will expect this to be a RocksDB options file and use it. If you are using the standalone cozo executable, you will get a log message if this feature is activated.

Note that improperly set options can make your database misbehave! In general, you should run your database once, copy the options file from data/OPTIONS-XXXXXX from within your database directory, and use that as a base for your customization. If you are not an expert on RocksDB, we suggest you limit your changes to adjusting those numerical options that you at least have a vague understanding.


CozoDB consists of three layers stuck on top of each other, with each layer only calling into the layer below:

(User code)
Language/environment wrapper
Query engine
Storage engine
(Operating system)

Storage engine

The storage engine defines a storage trait for the storage backend, which is an interface with required operations, mainly the provision of a key-value store for binary data with range scan capabilities. There are various implementations:

  • In-memory, non-persistent backend
  • SQLite storage backend
  • RocksDB storage backend
  • Sled storage backend
  • TiKV distributed storage backend

Depending on the build configuration, not all backends may be available in a binary release. The SQLite backend is special in that it is also used as the backup file format, which allows the exchange of data between databases with different backends. If you are using the database embedded in Rust, you can even provide your own custom backend.

The storage engine also defines a row-oriented binary data format, which the storage engine implementation does not need to know anything about. This format contains an implementation of the memcomparable format used for the keys, which enables the storage of rows of data as binary blobs that, when sorted lexicographically, give the correct order. This also means that data files for the SQLite backend cannot be queried with SQL in the usual way, and access must be through the decoding process in CozoDB.

Query engine

The query engine part provides various functionalities:

  • function/aggregation/algorithm definitions
  • database schema
  • transaction
  • query compilation
  • query execution

This part is where most of the code of CozoDB is concerned. The CozoScript manual has a chapter about the execution process.

Users interact with the query engine with the Rust API.

Language/environment wrapper

For all languages/environments except Rust, this part just translates the Rust API into something that can be easily consumed by the targets. For Rust, there is no wrapper. For example, in the case of the standalone server, the Rust API is translated into HTTP endpoints, whereas in the case of NodeJS, the (synchronous) Rust API is translated into a series of asynchronous calls from the JavaScript runtime.

If you want to make CozoDB usable in other languages, this part is where your focus should be. Any existing generic interop libraries between Rust and your target language would make the job much easier. Otherwise, you can consider wrapping the C API, as this is supported by most languages. For the languages officially supported, only Golang wraps the C API directly.

Status of the project

CozoDB is still very young, but we encourage you to try it out for your use case. Any feedback is welcome.

Versions before 1.0 do not promise syntax/API stability or storage compatibility.


Licensing and contributing

This project is licensed under MPL-2.0 or later. See here if you are interested in contributing to the project.

Mozilla Public License Version 2.0 ================================== 1. Definitions -------------- 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. 1.3. "Contribution" means Covered Software of a particular Contributor. 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. "Incompatible With Secondary Licenses" means (a) that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or (b) that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. "Executable Form" means any form of the work other than Source Code Form. 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" means this document. 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. "Modifications" means any of the following: (a) any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or (b) any new file in Source Code Form that contains any Covered Software. 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. "Source Code Form" means the form of the work preferred for making modifications. 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions -------------------------------- 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: (a) under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and (b) under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: (a) for any code that a Contributor has removed from Covered Software; or (b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or (c) under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities ------------------- 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: (a) such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and (b) You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation --------------------------------------------------- If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination -------------- 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. ************************************************************************ * * * 6. Disclaimer of Warranty * * ------------------------- * * * * Covered Software is provided under this License on an "as is" * * basis, without warranty of any kind, either expressed, implied, or * * statutory, including, without limitation, warranties that the * * Covered Software is free of defects, merchantable, fit for a * * particular purpose or non-infringing. The entire risk as to the * * quality and performance of the Covered Software is with You. * * Should any Covered Software prove defective in any respect, You * * (not any Contributor) assume the cost of any necessary servicing, * * repair, or correction. This disclaimer of warranty constitutes an * * essential part of this License. No use of any Covered Software is * * authorized under this License except under this disclaimer. * * * ************************************************************************ ************************************************************************ * * * 7. Limitation of Liability * * -------------------------- * * * * Under no circumstances and under no legal theory, whether tort * * (including negligence), contract, or otherwise, shall any * * Contributor, or anyone who distributes Covered Software as * * permitted above, be liable to You for any direct, indirect, * * special, incidental, or consequential damages of any character * * including, without limitation, damages for lost profits, loss of * * goodwill, work stoppage, computer failure or malfunction, or any * * and all other commercial damages or losses, even if such party * * shall have been informed of the possibility of such damages. This * * limitation of liability shall not apply to liability for death or * * personal injury resulting from such party's negligence to the * * extent applicable law prohibits such limitation. Some * * jurisdictions do not allow the exclusion or limitation of * * incidental or consequential damages, so this exclusion and * * limitation may not apply to You. * * * ************************************************************************ 8. Litigation ------------- Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. 9. Miscellaneous ---------------- This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License --------------------------- 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice ------------------------------------------- This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice --------------------------------------------------------- This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.


使用 Datalog 作为查询语言的高性能·关系型·可嵌入式·图数据库,还可进行历史穿梭查询 expand collapse
Rust and 6 more languages

Releases (4)





Load More
can not load any more
马建仓 AI 助手


344bd9b3 5694891 D2dac590 5694891