igraph / python-igraph

Python interface for igraph
GNU General Public License v2.0
1.31k stars 249 forks source link

Feature Request: Object Graph Model #765

Closed u3Izx9ql7vW4 closed 8 months ago

u3Izx9ql7vW4 commented 8 months ago

What is the feature or improvement you would like to see? An object graph model similar to Neo4j's neomodel package. Here's an example of the API lifted from their documentation:

Defining Nodes:

from neomodel import (config, StructuredNode, StringProperty, IntegerProperty,
    UniqueIdProperty, RelationshipTo)

class Country(StructuredNode):
    code = StringProperty(unique_index=True, required=True)

class City(StructuredNode):
    name = StringProperty(required=True)
    country = RelationshipTo(Country, 'FROM_COUNTRY')

class Person(StructuredNode):
    uid = UniqueIdProperty()
    name = StringProperty(unique_index=True)
    age = IntegerProperty(index=True, default=0)

    # traverse outgoing IS_FROM relations, inflate to Country objects
    country = RelationshipTo(Country, 'IS_FROM')

    # traverse outgoing LIVES_IN relations, inflate to City objects
    city = RelationshipTo(City, 'LIVES_IN')

Create, Update, Delete operations

jim = Person(name='Jim', age=3).save() # Create
jim.age = 4
jim.save() # Update, (with validation)
jim.delete()
jim.refresh() # reload properties from the database
jim.element_id # neo4j internal element id

Retrieving Nodes

# Return all nodes
all_nodes = Person.nodes.all()

# Returns Person by Person.name=='Jim' or raises neomodel.DoesNotExist if no match
jim = Person.nodes.get(name='Jim')

# Will return None unless "bob" exists
someone = Person.nodes.get_or_none(name='bob')

# Will return the first Person node with the name bob. This raises neomodel.DoesNotExist if there's no match.
someone = Person.nodes.first(name='bob')

# Will return the first Person node with the name bob or None if there's no match
someone = Person.nodes.first_or_none(name='bob')

# Return set of nodes
people = Person.nodes.filter(age__gt=3)

Relationships

germany = Country(code='DE').save()
jim.country.connect(germany)
berlin = City(name='Berlin').save()
berlin.country.connect(germany)
jim.city.connect(berlin)

if jim.country.is_connected(germany):
    print("Jim's from Germany")

for p in germany.inhabitant.all():
    print(p.name) # Jim

len(germany.inhabitant) # 1

# Find people called 'Jim' in germany
germany.inhabitant.search(name='Jim')

# Find all the people called in germany except 'Jim'
germany.inhabitant.exclude(name='Jim')

# Remove Jim's country relationship with Germany
jim.country.disconnect(germany)

usa = Country(code='US').save()
jim.country.connect(usa)
jim.country.connect(germany)

# Remove all of Jim's country relationships
jim.country.disconnect_all()

jim.country.connect(usa)
# Replace Jim's country relationship with a new one
jim.country.replace(germany)

Use cases for the feature The above API is a little easier to work with when dealing with objects, and offers greater flexibility than the array representation found in igraph's documentation for both adding edges and setting attributes.

Graphs with many hierarchical structures, such as Countries > States > Municipals > Cities > Groups > Persons may be easier to construct with an OGM-based model than igraph's existing method.

References Neomodels Github Neomodel's documentation Neomodel's Getting Started Examples

iosonofabio commented 8 months ago

Thank you, this is useful reference but you are requesting to change pretty much all core functions, data structures, and concepts.

I can't imagine any of us having time for such a broad restructuring, esp. Since @ntamas is already redesigning the Python interface. But point taken, a few ideas might turn out useful.

I'll leave open in case someone else wants to comment.

ntamas commented 8 months ago

I agree with @iosonofabio and building an object-graph model is probably outside the context of python-igraph; the goal of this package is to provide a Python wrapper to the igraph C library and not to build an API to an underlying relational database. Closing the issue to keep the issue tracker clean but feel free to comment nevertheless.

u3Izx9ql7vW4 commented 8 months ago

Thank you, this is useful reference but you are requesting to change pretty much all core functions, data structures, and concepts.

I can't imagine any of us having time for such a broad restructuring, esp. Since @ntamas is already redesigning the Python interface. But point taken, a few ideas might turn out useful.

I'll leave open in case someone else wants to comment.

I see thanks for your feedback. May I ask if the redesign of the Python interface that's currently under way will change the way edges and nodes are created and connected, as presently reflected in igraph's documentation? The reason I ask is that I may build an adapter on top of igraph, as I have existing code that uses Neo4j that needs to be migrated to something faster, and ideally I'd wait until igraph's api is stable

iosonofabio commented 8 months ago

Don't worry too much and migrate now, I'd say. The current codebase works and will do so in the foreseeable future.