Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

what is the correct way to write get_or_create_edge #266

Open
rrmerugu opened this issue Jan 31, 2018 · 1 comment
Open

what is the correct way to write get_or_create_edge #266

rrmerugu opened this issue Jan 31, 2018 · 1 comment

Comments

@rrmerugu
Copy link

rrmerugu commented Jan 31, 2018

I wrote get_or_create_vertex and it works fine (at least I can see the data correctly)

# this works great 
def orientdb_get_or_create_vertex(vertex=None, **kwargs):
    link_data = vertex.query(**kwargs).all()
    if link_data:
        link = link_data[0]
    else:
        link = vertex.create(
            **kwargs
        )
    return link

But I could not figure out a way to do get_or_create_edge. Usingedge.create(_from, _to) directly is creating duplications every time I run the script to update the data from mongo to orientdb(selected data only). how do I implement orientdb_relation_create_edge ?

def orientdb_relation_create_edge(g=None, edge=None, _from=None, _to=None):
    e = g.inE(_to, [edge]).outE(_from, [edge]).all() # not sure ?
    print (e)
    if e:
        e = e[0]
    else:
        e = edge.create(_from, _to) # using this directly is creating duplications, 
    return e
@acriptis
Copy link

acriptis commented Feb 2, 2018

This code quite dirty (you may need some adaptations), but it works well for me (I use it as base class for all Edge classes in OGM):

# Create Edge Class
class RelationshipGetOrCreateInterface(object):
    @classmethod
    def get_or_create(cls, from_node, to_node, **kwargs):
        """
        Get first or create according to criteria

        :param from_node:
        :param to_node:
        :param kwargs:
        :return: created or found edge object
        """
        get_query_dict = {
            "in": to_node,
            "out": from_node,
        }

        get_query_dict.update(kwargs)
        # import ipdb; ipdb.set_trace()

        # slow:
        # results = cls.objects.query(**get_query_dict)

        # optimized:
        results = cls.filter(from_node, to_node, **kwargs)
        count = len(results)

        if count>0:
            # get first
            if count > 1:
                LOG.debug("Multiple results for get_or_create filter query "
                       "return the first object only!!!")
                LOG.debug(get_query_dict)
            # found something, return first
            LOG.debug("Get the EDGE %s from DB! Data: %s" % (cls.__name__, results[0].__dict__))

            return results[0]
        else:
            # create
            return cls.create(from_node, to_node, **kwargs)

    @classmethod
    def filter(cls, from_node, to_node, **kwargs):
        rel_class_filter = cls.registry_name
        additional_filter_of_relation = ""
        if kwargs:
            # support only equality filters/ only strings!!!!
            for k,v in kwargs.items():
                additional_filter_of_relation += " and %s=%s" % (k, json.dumps(unicode(v)))

        if hasattr(to_node, "_id"):
            to_node_id = to_node._id
        elif hasattr(to_node, "id"):
            to_node_id = to_node.id
        else:
            raise Exception("Can not detect id for node: %s" % to_node)

        if hasattr(from_node, "_id"):
            from_node_id = from_node._id
        elif hasattr(from_node, "id"):
            from_node_id = from_node.id
        else:
            raise Exception("Can not detect id for node: %s" % from_node)
        command_str = "SELECT expand(outE('%s')[in=%s%s]) FROM %s" % (rel_class_filter,
                                                                      to_node_id,
                                                                      additional_filter_of_relation,
                                                                      from_node_id)
        LOG.info(command_str)
        try:
            orient_records = cls.objects.g.client.query(command_str)
            results = cls.objects.g.edges_from_records(orient_records)
            return results
        except Exception as e:           
            import socket
            LOG.warning(e)
            LOG.warning("Error happened during orient command: %s" % command_str)            
            return []

    @classmethod
    def filter_by_attributes(cls, **kwargs):
        """
        more flexible but slow method of filtering Edges in orientDB, must be used when it is impossible
        to filter by to_node and from_node (which makes query much faster)

        :param kwargs:
        :return: ORM edges
        """
        orient_records = cls.objects.query(**kwargs)
        return orient_records

    @classmethod
    def create(cls, from_node, to_node, **kwargs):
        edge = graph.create_edge(
            cls,
            from_node,
            to_node,
            **kwargs)
        LOG.debug("Creating a new Relationshisp in GraphDB: %s" % cls.__name__)
        str_from = str(from_node)
        str_to = str(to_node)        
        if kwargs:
            LOG.debug(kwargs)
        return edge

    # fast but hardcody method which makes possible to search relations with filtering
    # by string attribute
    @classmethod
    def get(cls, from_node, to_node, **kwargs):
        """
        Gets edge according to filter criteria
        Raises Exception if Not Found or Multiple Objects returned
        :param kwargs:
        :return:
        """
        results = cls.filter(from_node, to_node, **kwargs)        
        return cls.handle_results_for_get(results, from_node, to_node, **kwargs)

    def handle_results_for_get(self, results, from_node, to_node, **kwargs):
        count = len(results)
        if count==1:
            # found something
            LOG.info("Got the node from DB! %s" % kwargs)
            return results[0]
        elif count>1:
            LOG.exception("Multiple results for get filter query "
                          "kwargs: %s" % kwargs)
            for each_obj in results:
                LOG.debug(each_obj)
            raise Exception("Multiple Objects in get method!")
        else:
            # No objects found
            raise Exception("No objects according to filtering criteria: %s" % kwargs)

Would be happy to get feedback with improvements for the snippet class above

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants