summaryrefslogtreecommitdiff
path: root/linkmerge.py
blob: 3cfe1f14a7a59b0e96faf0da46e3541889c21068 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108

import freebase, freebase.schema
from freebase.api import LITERAL_TYPE_IDS, MetawebError

from copy import deepcopy
import itertools
import logging

ALL_LINKS_QUERY = [{"type": "/type/link",
                    "source": {"id" : None},
                    "target": {"id" : None},
                    "target_value": None,
                    "master_property": { "id" : None, "expected_type" : None, "unique" : None },
                    "operation": None,
                    "valid": True }]

def merge(s, amoeba_id, target_id):
    # In merging, we'll use the analogy of phagocytosis.
    # http://en.wikipedia.org/wiki/Phagocytosis
    # In this example, the amoeba is the main guy who is swallowing the target

    # In cases where there is no merging problem, it doesn't matter who is the
    # amoeba and who is the target, but the final merge product will be in the amoeba

    # this merging will be done using links
    # effectively, we want to move everything that links to the target
    # and link it to the amoeba. This does present some issues:
    # some things just can't be moved (/en keys, for example).
    
    target_source_l, target_target_l, target_target_v_l = get_all_links(target_id)
    amoeba_source_l, amoeba_target_l, amoeba_target_v_l = get_all_links(amoeba_id)

    total_delete_query = {}
    total_write_query = { "id" : amoeba_id }

    # let's redirect all source and target links on target to amoeba
    #print [i for i in target_source_l]; print
    for link in target_source_l:
        # try this
        if link.master_property.expected_type != "/type/text" and \
            link.master_property.expected_type != "/type/key" and \
            link.master_property.id != "/type/object/permission" and \
            (not (link.master_property.unique and exists(amoeba_source_l, amoeba_target_l, link.master_property.id))):
            prop = link.master_property.id
            print prop
            current_prop = total_write_query.get(prop, [])
            current_prop.append({"id" : link.target.id, "connect" : "replace"})
            total_write_query[prop] = current_prop
            
            to_delete_prop = total_delete_query.get(prop, [])
            to_delete_prop.append({"id" : link.target.id, "connect" : "delete"})
            total_delete_query[prop] = to_delete_prop
            
    for link in target_target_l:
        if link.master_property.expected_type != "/type/text" and \
            link.master_property.expected_type != "/type/key" and \
            link.master_property.id != "/type/object/permission":
            
            prop = "!" + link.master_property.id
            print prop
            current_prop = total_write_query.get(prop, [])
            current_prop.append({"id" : link.source.id, "connect" : "replace"})
            total_write_query[prop] = current_prop
            
            to_delete_prop = total_delete_query.get(prop, [])
            to_delete_prop.append({"id" : link.source.id, "connect" : "delete"})
            total_delete_query[prop] = to_delete_prop
    
    # delete old
    badpropnames = set([])
    for propname, guys in total_delete_query.iteritems():
        new = dict({propname:guys, "id":target_id})
        try:
            s.mqlwrite(new)
        except MetawebError, me:
            print "Oh well, %s failed. %s" % (propname, me)
            badpropnames.add(propname)
    for badprop in badpropnames:
        del total_write_query[badprop]
    s.mqlwrite(total_write_query)
        
    
def exists(source_links, target_links, property_id):
    print "testing", property_id
    for link in itertools.chain(source_links, target_links):
        if link.master_property.id == property_id:
            if link.target and link.source:
                print "outta here", property_id
                return True
            return False
    return False
    


def get_all_links(the_id):
    source, target, target_value = [deepcopy(ALL_LINKS_QUERY) for i in range(3)]
    source[0].update(source={"id" : the_id})
    target[0].update(target={"id" : the_id})
    target_value[0].update(target_value={"id" : the_id })

    return (s.mqlreaditer(source),
            s.mqlreaditer(target),
            s.mqlreaditer(target_value))


if __name__ == '__main__':
    s = freebase.api.HTTPMetawebSession("http://sandbox-freebase.com")
    merge(s, "/guid/9202a8c04000641f800000000bc3141d", "/guid/9202a8c04000641f800000000aa5533e")