DualLoop / src / preprocessing.py
preprocessing.py
Raw
#
#     dualloop
#
#        File:  preprocessing.py
#
#     Authors: Deleted for purposes of anonymity
#
#     Proprietor: Deleted for purposes of anonymity --- PROPRIETARY INFORMATION
#
# The software and its source code contain valuable trade secrets and shall be maintained in
# confidence and treated as confidential information. The software may only be used for
# evaluation and/or testing purposes, unless otherwise explicitly stated in the terms of a
# license agreement or nondisclosure agreement with the proprietor of the software.
# Any unauthorized publication, transfer to third parties, or duplication of the object or
# source code---either totally or in part---is strictly prohibited.
#
#     Copyright (c) 2019 Proprietor: Deleted for purposes of anonymity
#     All Rights Reserved.
#
# THE PROPRIETOR DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS FOR A PARTICULAR PURPOSE AND THE WARRANTY AGAINST LATENT
# DEFECTS, WITH RESPECT TO THE PROGRAM AND ANY ACCOMPANYING DOCUMENTATION.
#
# NO LIABILITY FOR CONSEQUENTIAL DAMAGES:
# IN NO EVENT SHALL THE PROPRIETOR OR ANY OF ITS SUBSIDIARIES BE
# LIABLE FOR ANY DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES
# FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF INFORMATION, OR
# OTHER PECUNIARY LOSS AND INDIRECT, CONSEQUENTIAL, INCIDENTAL,
# ECONOMIC OR PUNITIVE DAMAGES) ARISING OUT OF THE USE OF OR INABILITY
# TO USE THIS PROGRAM, EVEN IF the proprietor HAS BEEN ADVISED OF
# THE POSSIBILITY OF SUCH DAMAGES.
#
# For purposes of anonymity, the identity of the proprietor is not given herewith.
# The identity of the proprietor will be given once the review of the
# conference submission is completed.
#
# THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
#

import json
import multiprocessing

from SPARQLWrapper import SPARQLWrapper, JSON
import spacy
nlp = spacy.load('en_core_web_lg')
import wordsegment
wordsegment.load()
import re

import numpy as np


import rdflib
from rdflib import Graph

# from rdf2vec import graph
# from rdf2vec import rdf2vec

from sentence_transformers import SentenceTransformer
sbert = SentenceTransformer('sentence-transformers/paraphrase-MiniLM-L6-v2')

from nltk.stem import PorterStemmer
porter = PorterStemmer()

from nltk.corpus import wordnet

cfg = None


def query_ontology():
    sparql = SPARQLWrapper(cfg.RDF4J_SERVER + "/rdf4j-server/repositories")    
    sparql.setReturnFormat(JSON)
    results = sparql.query().convert()

    ontology_list = []

    for repository in results['results']['bindings']:
        #print(repository)
        ontology = {}
        ontology['id'] = repository['id']['value']
        ontology['title'] = repository['title']['value']        
        ontology['uri'] = repository['uri']['value']

        ontology_list.append(ontology)
        
    return ontology_list

def query_class(ontology):
    print(ontology)
    sparql = SPARQLWrapper(ontology)
    sparql.setQuery(
        """
        PREFIX owl: <http://www.w3.org/2002/07/owl#>
        SELECT ?class
        WHERE {
            ?class rdf:type owl:Class.
          FILTER (!isBlank(?class))
        }
        """
    )
    
    sparql.setReturnFormat(JSON)
    results = sparql.query().convert()
    
    class_list = []
    for v in results["results"]["bindings"]:
        class_list.append(v["class"]["value"])
    
    return class_list


def get_subclasses(ontology, class_prefix, class_name):
    sparql = SPARQLWrapper(ontology)
        
    queryStatement = """
    PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>       
    PREFIX owl: <http://www.w3.org/2002/07/owl#>
    PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
    PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
    PREFIX pre: <%(class_prefix)s>

    SELECT ?subclass
    WHERE { ?subclass rdfs:subClassOf pre:%(class_name)s . }
    """ % {"class_prefix": class_prefix, "class_name" : class_name}      
    
    #print(queryStatement)
    sparql.setQuery(queryStatement)
    sparql.setReturnFormat(JSON)
    results = sparql.query().convert()
    
    class_list = []    
    for result in results["results"]["bindings"]:
        subclass = result['subclass']['value']
        class_list.append(subclass)

    return class_list

def get_superclasses(ontology, class_prefix, class_name):
    sparql = SPARQLWrapper(ontology)

    queryStatement = """
    PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>       
    PREFIX owl: <http://www.w3.org/2002/07/owl#>
    PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
    PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
    PREFIX pre: <%(class_prefix)s>
    SELECT ?superclass
    WHERE { 
    pre:%(class_name)s rdfs:subClassOf ?superclass .
    }
    """ % {"class_prefix": class_prefix, "class_name" : class_name}
    
    #print(queryStatement)
    sparql.setQuery(queryStatement)
    sparql.setReturnFormat(JSON)
    results = sparql.query().convert()    
    
    class_list = []    
    for result in results["results"]["bindings"]:
        subclass = result['superclass']['value']
        class_list.append(subclass)

    return class_list

def split_prefix_class_name(uri):
    tmp = uri.split("#",1)
    if len(tmp) == 2:
        class_prefix = uri.split("#",1)[0]  + "#"
        class_name = uri.split("#",1)[1]
    else:
        tmp = uri.split("/",-1)
        class_prefix = "/".join(tmp[:-1])  + "/"
        class_name = tmp[-1:][0]
    return class_prefix, class_name

def get_equivalent_classes(sparql_endpoint, class_prefix, class_name):
    sparql = SPARQLWrapper(sparql_endpoint)
    
    queryStatement = """
    PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>       
    PREFIX owl: <http://www.w3.org/2002/07/owl#>
    PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
    PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
    PREFIX pre: <%(class_prefix)s>
    select distinct ?property where {
        pre:%(class_name)s owl:equivalentClass ?obj .
        ?obj owl:unionOf ?c .
        ?c rdf:rest*/rdf:first ?property 
        }    """ % {"class_prefix": class_prefix, "class_name" : class_name}
        
    print(queryStatement)
    sparql.setQuery(queryStatement)
    
    sparql.setReturnFormat(JSON)
    results = sparql.query().convert()
    results = results["results"]["bindings"]
    results_clean = []
    if not results:
        return results_clean
    for i in results:
        _, v = split_prefix_class_name(i["property"]["value"])
        results_clean.append(v)
        
    return results_clean


def get_label(ontology, class_prefix, class_name):
    sparql = SPARQLWrapper(ontology)

    queryStatement = """
    PREFIX pre: <%(class_prefix)s>
    select ?label where {
        pre:%(class_name)s rdfs:label  ?label .
    }
    """ % {"class_prefix": class_prefix, "class_name" : class_name}

    #print(queryStatement)
    sparql.setQuery(queryStatement)
    sparql.setReturnFormat(JSON)
    results = sparql.query().convert()    
        
    items = results["results"]["bindings"]
    for item in items:
        return item['label']['value']

    return ""

def get_definition(ontology, class_prefix, class_name):
    sparql = SPARQLWrapper(ontology)

    queryStatement = """
        PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
        PREFIX obo-term: <http://purl.obolibrary.org/obo/>
        PREFIX pre: <%(class_prefix)s>
        select distinct ?definition where {
            pre:%(class_name)s  obo-term:IAO_0000115 ?definition .            
        }

        """ % {"class_prefix": class_prefix, "class_name" : class_name}

    # print(queryStatement)

    sparql.setQuery(queryStatement)
    sparql.setReturnFormat(JSON)
    results = sparql.query().convert()

    definitions = results["results"]["bindings"]
    for definition in definitions:
        return definition['definition']['value']

    return ""


def get_comment(ontology, class_prefix, class_name):
    sparql = SPARQLWrapper(ontology)

    queryStatement = """
    PREFIX pre: <%(class_prefix)s>
    select ?comment where {
        pre:%(class_name)s rdfs:comment  ?comment .
    }
    """ % {"class_prefix": class_prefix, "class_name" : class_name}

    #print(queryStatement)
    sparql.setQuery(queryStatement)
    sparql.setReturnFormat(JSON)
    results = sparql.query().convert()    
        
    comments = results["results"]["bindings"]
    for comment in comments:
        return comment['comment']['value']

    return ""

def get_relevant_synonyms(ontology, class_prefix, class_name):
    sparql = SPARQLWrapper(ontology)

    queryStatement = """
    PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>       
    PREFIX owl: <http://www.w3.org/2002/07/owl#>
    PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
    PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
    PREFIX pre: <%(class_prefix)s>
    SELECT ?label
    WHERE { 
        pre:%(class_name)s oboInOwl:hasRelatedSynonym  ?o .
        ?o rdfs:label ?label .    
    }
    """ % {"class_prefix": class_prefix, "class_name" : class_name}
    
    #print(queryStatement)
    sparql.setQuery(queryStatement)
    sparql.setReturnFormat(JSON)
    results = sparql.query().convert()    
    
    synonyms_list = []    
    for result in results["results"]["bindings"]:
        subclass = result['label']['value']
        synonyms_list.append(subclass)

    return synonyms_list

def get_properties(ontology, class_prefix, class_name):
    sparql = SPARQLWrapper(ontology)

    queryStatement = """
    PREFIX pre: <%(class_prefix)s>
    select distinct ?property where {
        ?property rdfs:domain pre:%(class_name)s .
    }
    """ % {"class_prefix": class_prefix, "class_name" : class_name}

    #print(queryStatement)
    sparql.setQuery(queryStatement)
    sparql.setReturnFormat(JSON)
    results = sparql.query().convert()    
        
    properties = []
    for result in results["results"]["bindings"]:
        full_uri = result['property']['value']
        prop = full_uri.split("#",1)[1]   
        properties.append(prop)
        
    return properties


def get_groundtruth(file, fix_uri):
    g=rdflib.Graph()
    
    print(file)
    
    g.parse(file)

    qres = g.query(
    """
    SELECT ?from ?to ?m
    WHERE {
    ?a a <http://knowledgeweb.semanticweb.org/heterogeneity/alignment#Cell>;
    <http://knowledgeweb.semanticweb.org/heterogeneity/alignment#measure> ?m ;
    <http://knowledgeweb.semanticweb.org/heterogeneity/alignment#entity1> ?from ;
    <http://knowledgeweb.semanticweb.org/heterogeneity/alignment#entity2> ?to. }
    """
    )

    if len(qres) == 0:
        qres = g.query(
        """
        SELECT ?from ?to ?m
        WHERE {
        ?a a <http://knowledgeweb.semanticweb.org/heterogeneity/alignmentCell>;
        <http://knowledgeweb.semanticweb.org/heterogeneity/alignmentmeasure> ?m ;
        <http://knowledgeweb.semanticweb.org/heterogeneity/alignmententity1> ?from ;
        <http://knowledgeweb.semanticweb.org/heterogeneity/alignmententity2> ?to. }
        """
        )
        
    matches = []
    for row in qres:     
        match = {}
        source_class = row[0]
        target_class = row[1]
        
        if fix_uri == True:
            match['source_class'] = source_class.strip().replace("#", "/#")
            match['target_class'] = target_class.strip().replace("#", "/#")
        else:
            match['source_class'] = source_class.strip()
            match['target_class'] = target_class.strip()
        
        matches.append(match)
        
    return matches    


def get_groundtruth_from_rdf4j(repository):
    sparql = SPARQLWrapper(repository)

    queryStatement = """
        SELECT ?entity1 ?entity2 
        WHERE {
            ?a a <http://knowledgeweb.semanticweb.org/heterogeneity/alignment#Cell>;
            <http://knowledgeweb.semanticweb.org/heterogeneity/alignment#entity1> ?entity1 ;
            <http://knowledgeweb.semanticweb.org/heterogeneity/alignment#entity2> ?entity2. }
        """    
    
    #print(queryStatement)
    sparql.setQuery(queryStatement)
    sparql.setReturnFormat(JSON)
    results = sparql.query().convert()    
    
    #print(results)
        
    matches = []
    for result in results["results"]["bindings"]:
        match = {}
        
        source_class = result['entity1']['value']
        target_class = result['entity2']['value']
                
        match['source_class'] = source_class
        match['target_class'] = target_class

        matches.append(match)
        
    return matches    


def split_name(n):
    sub_names = re.sub('([A-Z][a-z]+)', r' \1', re.sub('([A-Z]+)', r' \1', n)).split()
    return sub_names


def find_root_noun(spay_tokens):
    for token in spay_tokens:
        if token.dep_ == 'ROOT':
            return str(token)
        
    return None


class AlignmentProfile:
    def __init__(self):
        self.ontology_name = None
        self.uri = None
        self.class_prefix = None
        self.class_name = None
        self.class_name_words = None
        self.class_name_stemmed = None
        self.class_name_root = None
        self.acronym = None
        self.synonyms = None

        self.label = None
        self.label_words = None

        # self.definition = None

        self.comment = None

        self.subclasses = None
        self.superclasses = None
        self.properties = None

        # properties for the anatomy dataset
        # self.equivalent_classes = []
        # self.relevant_synonyms = []


        # produced embeddings
        # self.class_name_embedding = None
        # self.class_name_words_embedding = None
        # self.class_long_name_embedding = None
        # self.class_name_sbert_embedding = None
        # self.label_embedding = None
        # self.label_sbert_embedding = None
        # self.comment_embedding = None
        # self.comment_sbert_embedding = None

        # self.walk_embedding = None

def build_class_alignment_profile(ontology_name, class_uri, with_embedding):
    ap = AlignmentProfile()

    ap.ontology_name = ontology_name
    ap.uri = class_uri
    ap.class_prefix = class_uri.split("#",1)[0]+"#"

    ap.class_name = class_uri.split("#",1)[1]

    name_in_words = wordsegment.segment(ap.class_name)
    ap.class_name_words = ' '.join([str(elem) for elem in name_in_words])

    ap.class_name_stemmed = porter.stem(ap.class_name)
    ap.class_name_root = find_root_noun(nlp(ap.class_name))

    ap.acronym = ''.join([s[0] for s in re.sub('([A-Z][a-z]+)', r' \1', re.sub('([A-Z]+)', r' \1', ap.class_name)).split()])

    synonyms = []
    for syn in wordnet.synsets(ap.class_name):
        for lm in syn.lemmas():
            synonyms.append(lm.name())
    ap.synonyms = synonyms

    ap.label = get_label(ap.ontology_name, ap.class_prefix, ap.class_name)
    label_words = wordsegment.segment(ap.label)
    ap.label_words = ' '.join([str(elem) for elem in label_words])

    ap.comment = get_comment(ap.ontology_name, ap.class_prefix, ap.class_name)

    ap.subclasses = get_subclasses(ap.ontology_name, ap.class_prefix, ap.class_name)
    ap.superclasses = get_superclasses(ap.ontology_name, ap.class_prefix, ap.class_name)
    ap.properties = get_properties(ap.ontology_name, ap.class_prefix, ap.class_name)

    # ap.definition = get_definition(ap.ontology_name, ap.class_prefix, ap.class_name)
    # ap.equivalent_classes = get_equivalent_classes(ap.ontology_name, ap.class_prefix, ap.class_name)
    # ap.relevant_synonyms = get_relevant_synonyms(ap.ontology_name, ap.class_prefix, ap.class_name)

    # embedding feature
    # if with_embedding:
    #     ap.class_name_embedding = nlp(ap.class_name_words).vector
    #     ap.label_embedding = nlp(ap.label_words).vector
    #     ap.comment_embedding = nlp(ap.comment).vector
    #
    #     ap.class_name_sbert_embedding = sbert.encode(ap.class_long_name)
    #     ap.label_sbert_embedding = sbert.encode(ap.label)
    #     ap.comment_sbert_embedding = sbert.encode(ap.comment)

    return ap


def build_rdf2vec(ontology_name, classes):
    endpoint = ontology_name + "/statements"
    g = Graph()
    g.parse(endpoint)
    
    kg = graph.rdflib_to_kg(g, label_predicates=[])
    
    transformer = rdf2vec.RDF2VecTransformer(wl=False, max_path_depth=2, sg=1)
    walk_embeddings = transformer.fit_transform(kg, classes)    
    
    print(len(walk_embeddings))
    
    return walk_embeddings
    
def build_alignment_profile(ontology_name, with_embedding):
    class_list = query_class(ontology_name) 

    #print(class_list)

    # build the graph embedding for rdf tripes in the ontology
    #rdf_embeddings = build_rdf2vec(ontology_name, class_list)
    #

    # for each class
    profiles = []
    for index, class_uri in enumerate(class_list):
        #print(class_uri)
        profile = build_class_alignment_profile(ontology_name, class_uri, with_embedding)

        # query the rdf2vec embedding for this class
        #profile.walk_embedding = rdf_embeddings[index]

        profiles.append(profile)

    return profiles