def query(self, result_atomspace, query): res_set = self.intersect(query) # add all possible results to tmp atomspace and run query # what is called filter step in graph indexing literature tmp = AtomSpace() atom_str = self._storage.get_atoms(res_set) for item in atom_str: tmp.add_atom(scheme_eval_h(tmp, item)) # pack query in BindLink q = tmp.add_link(types.BindLink, [query, query]) results = execute_atom(tmp, q) result_atoms = set() for atom in results.out: result_atoms.add(result_atomspace.add_atom(atom)) return result_atoms
def add_to_atomspace(atoms: set[Atom] | list[Atom], atomspace: AtomSpace) -> None: """Add all atoms to the atomspace.""" for atom in atoms: atomspace.add_atom(atom)
class Index: def __init__(self, storage: Storage): self.pattern_space = AtomSpace() self.semantic_space = AtomSpace() # storage maps index to atom self._storage = storage # index maps subgraph pattern to matching atom ids self._index = dict() def add_toplevel_pattern(self, atom): args = [ self.pattern_space.add_node(types.VariableNode, '$X' + str(i)) for i in range(atom.arity) ] l = self.pattern_space.add_link(atom.type, args) bindlink = self.pattern_space.add_link(types.BindLink, [l, l]) self.add_pattern(bindlink) def add_semantic_pattern(self, atom): # find all nodes, that inherit from some atom from semantic atomspace # replace such atoms by variable nodes result = replace(atom, self.semantic_space, self.pattern_space, dict()) pattern = self.pattern_space.add_link(types.BindLink, [result, result]) self.add_pattern(pattern) def add_data(self, data): idx, new = self._storage.add_atom(data) if not new: return assert data.is_link() # self.add_toplevel_pattern(data) self.add_semantic_pattern(data) tmp = create_child_atomspace(self.pattern_space) content = tmp.add_atom(data) self.update_index(tmp, content, idx) def update_index(self, atomspace, data, idx): for pat in self._index.keys(): match = execute_atom(atomspace, pat) # patterns can match patterns, so check: for m in match.out: if m == data: self._index[pat].add(idx) def intersect(self, query): """ Extracts relevant patterns to the query and intersects their indices returns set of atoms ids """ # put query in tmp atomspace, check if there are relevant patterns tmp = create_child_atomspace(self.pattern_space) q = tmp.add_atom(rename(tmp, self.pattern_space, query)) # check query for exact match: exact_match = execute_atom(tmp, tmp.add_link(types.BindLink, [q, q])) for m in exact_match.out: return self._index[self.pattern_space.add_link( types.BindLink, [m, m])] # no exact match: search among all patterns # todo: search subgraphs res_set = None for pat, idx in self._index.items(): # pattern is relevant if it matches query match = execute_atom(tmp, pat) for m in match.out: if hash(m) == hash(q): if res_set is None: res_set = idx else: res_set = res_set.intersection(idx) return res_set def query(self, result_atomspace, query): res_set = self.intersect(query) # add all possible results to tmp atomspace and run query # what is called filter step in graph indexing literature tmp = AtomSpace() atom_str = self._storage.get_atoms(res_set) for item in atom_str: tmp.add_atom(scheme_eval_h(tmp, item)) # pack query in BindLink q = tmp.add_link(types.BindLink, [query, query]) results = execute_atom(tmp, q) result_atoms = set() for atom in results.out: result_atoms.add(result_atomspace.add_atom(atom)) return result_atoms def update_index_dual_link(self, content): # doesn't work d = tmp.add_link(types.DualLink, [content]) # result is a set of conditional parts from pattens(GetLinks) pattern_set = execute_atom(tmp, d) # todo: create a new pattern assert len(pattern_set.out) for pattern in pattern_set.out: get_link = self.pattern_space.add_link(types.GetLink, pattern) self._index[get_link].add(data) def add_pattern(self, pat): assert pat.type == types.BindLink atom = self.pattern_space.add_atom(pat) if atom not in self._index: self._index[atom] = set()