• Stars
    star
    182
  • Rank 210,020 (Top 5 %)
  • Language
    Python
  • License
    MIT License
  • Created almost 7 years ago
  • Updated over 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

sqlite based graph database for storing native python objects and their relationships to each other

graphdb

Downloads Downloads Downloads

A sqlite based graph database for storing native python objects and their relationships to each other.

How to install it?

pip install graphdb

How to use it?

In [1]: # import GraphDB

In [2]: from graphdb import GraphDB

In [3]: # initialize a database

In [4]: db = GraphDB('/tmp/test_graph.db') # uses ':memory:' if no path

In [5]: # you can store relations between native python objects

In [6]: for a in range(10):
   ...:     b = a + 1
   ...:     print(a, b)
   ...:     db.store_relation(a, 'comes_before', b)
   ...:
0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10

In [7]: # you have as many relationships between objects as you want

In [8]: def is_prime(a):
   ...:     ''' returns true if 'a' is prime '''
   ...:     return a>1 and all(a % i for i in range(2, a))
   ...:
   ...: def preceding_primes(a):
   ...:     ''' returns a list of prime numbers less than 'a' '''
   ...:     return [i for i in range(a) if is_prime(i)]
   ...:
   ...: for i in range(11):
   ...:     for p in preceding_primes(i):
   ...:         db.store_relation(i, 'preceding_prime', p)
   ...:

In [9]: # queries to the database are done through attribute chains

In [10]: db(7).comes_before.preceding_prime(list)
Out[10]: [2, 3, 5, 7]

In [11]: # to break the query into pieces, we start with the starting point

In [12]: db(7)(list) # tells the db to start the query at this object
Out[12]: [7]

In [13]: # now we add 'comes_before' to hop to whatever object '7 comes_before'

In [14]: db(7).comes_before(list)
Out[14]: [8]

In [15]: # then we add the 'preceding_prime' to get all connected primes to 8

In [16]: db(7).comes_before.preceding_prime(list)
Out[16]: [2, 3, 5, 7]

In [17]: # since every query outputs iterable elements, it doesn't matter how
    ...: # many elements you're currently at because elements only stay as long
    ...: # as the query applies to them

In [18]: db(7).comes_before.preceding_prime.comes_before(list)
Out[18]: [3, 4, 6, 8]

In [19]: db(7).comes_before.preceding_prime.comes_before.comes_before(list)
Out[19]: [4, 5, 7, 9]

In [20]: db(7).comes_before.preceding_prime.comes_before.comes_before.comes_before(list)
Out[20]: [5, 6, 8, 10]

In [21]: # so what if we add one more 'comes_before' even though we never
    ...: # assigned '10' a relationship to refer to?

In [22]: db(7).comes_before.preceding_prime.comes_before.comes_before.comes_before.comes_before(list)
Out[22]: [6, 7, 9]

In [23]: # the query simply drops that node since its relational path didn't
    ...: # apply to the 4th result

In [24]: # Why does every query end with '(list)'?

In [25]: # graphdb sets up queries so you can continue to get each next step
    ...: # until you add '()' to the end of it which then tells graphdb that
    ...: # you want a materialized view of that spot.
    ...:
    ...: # The reason why in this demo '(list)' was being added instead of
    ...: # '()' was because by default, graphdb returns a native python
    ...: # generator so you can iterate through each individual object

In [26]: # just to demonstrate normal behavior
    ...: db(7).comes_before()
Out[26]: <generator object VList.__call__.<locals>.<genexpr> at 0x103336f68>

In [27]: # so we could technically do
    ...: list(db(7).comes_before())
Out[27]: [8]

In [28]: # or the more natural feeling

In [29]: db(7).comes_before(list)
Out[29]: [8]

In [30]: # 'list' isn't the only type you can pass into the query breakpoint,
    ...: # any container-like type you want to use should work

In [31]: db(7).comes_before(set)
Out[31]: {8}

In [32]: # Are there any filtering mechanisms that can be used to cut down how
    ...: # many relations graphdb queries produce?

In [33]: # '.where()' is used to filter relationships. So, for example:

In [34]: # what we're gonna filter
    ...: db(8).preceding_prime(list)
Out[34]: [2, 3, 5, 7]

In [35]: # this filters preceding_primes of 8 which are larger than 5
    ...: db(8).preceding_prime.where(lambda i:i>5)(list)
Out[35]: [7]

In [36]: # or we can filter items based on their linked objects
    ...: db(8).preceding_prime.where('comes_before', lambda i:i>5)(list)
Out[37]: [5, 7]