Commit 24a4e14d authored by Anze Vavpetic's avatar Anze Vavpetic

added database to orange converter

parent 55a79947
......@@ -3,6 +3,9 @@ from django import forms
import mysql.connector as sql
class DBConnection:
'''
Database credentials.
'''
def __init__(self, user, password, host, database):
self.user = user
self.password = password
......@@ -14,6 +17,19 @@ class DBConnection:
class DBContext:
def __init__(self, connection):
'''
Initializes the fields:
tables: list of selected tables
cols: dict of columns for each table
all_cols: dict of columns for each table (even unselected)
col_vals: available values for each table/column
connected: dict of table pairs and the connected columns
fkeys: foreign keys in a given table
pkeys: private key for a given table
target_table: selected table for learning
target_att: selected column for learning
target_att_val: selected target att value
'''
self.connection = connection
con = connection.connect()
cursor = con.cursor()
......@@ -26,9 +42,10 @@ class DBContext:
self.all_cols = dict(self.cols)
self.col_vals = {}
for table, cols in self.cols.items():
self.col_vals[table] = {}
for col in cols:
cursor.execute("SELECT DISTINCT %s FROM %s" % (col, table))
self.col_vals[col] = [val for (val,) in cursor]
self.col_vals[table][col] = [val for (val,) in cursor]
self.connected = {}
cursor.execute(
"SELECT table_name, column_name, referenced_table_name, referenced_column_name \
......@@ -52,6 +69,9 @@ class DBContext:
con.close()
def update(self, postdata):
'''
Updates the default selections with user's selections.
'''
widget_id = postdata.get('widget_id')[0]
self.target_table = postdata.get('target_table%s' % widget_id)[0]
self.target_att = postdata.get('target_att%s' % widget_id)[0]
......
......@@ -4,26 +4,46 @@ Classes for handling DBContexts for ILP systems.
@author: Anze Vavpetic <anze.vavpetic@ijs.si>
'''
class ILP_DBContext:
class Converter:
'''
Base class for converting between a given database context (selected tables, columns, etc)
to inputs acceptable by a specific ILP system.
If possible, all subclasses should use lazy selects by forwarding the DB connection.
Base class for converters.
'''
def __init__(self, dbcontext, settings={}):
def __init__(self, dbcontext):
self.db = dbcontext
self.connection = dbcontext.connection.connect()
self.cursor = self.connection.cursor()
self.settings = settings
def __del__(self):
def __del__(self):
self.connection.close()
def rows(self, table, cols):
def rows(self, table, cols):
self.cursor.execute("SELECT %s FROM %s" % (','.join(cols), table))
return [cols for cols in self.cursor]
def fetch_types(self, table, cols):
'''
Returns a dictionary of field types for the given table and columns.
'''
from mysql.connector import FieldType
c = self.cursor
c.execute('SELECT %s FROM %s LIMIT 1' % (','.join(cols), table))
c.fetchall()
types = {}
for desc in self.cursor.description:
types[desc[0]] = FieldType.get_info(desc[1])
return types
class ILP_Converter(Converter):
'''
Base class for converting between a given database context (selected tables, columns, etc)
to inputs acceptable by a specific ILP system.
If possible, all subclasses should use lazy selects by forwarding the DB connection.
'''
def __init__(self, *args, **kwargs):
self.settings = kwargs.pop('settings') if kwargs else {}
Converter.__init__(self, *args, **kwargs)
def user_settings(self):
return [':- set(%s,%s).' % (key,val) for key, val in self.settings.items()]
......@@ -63,7 +83,7 @@ class ILP_DBContext:
return ['%s_%s(%s, %s) :-' % (table, att, var_table, var_att),
'\t%s(%s).' % (table, ','.join([att.capitalize() if att!=pk else var_table for att in self.db.cols[table]]))]
class RSD_DBContext(ILP_DBContext):
class RSD_Converter(ILP_Converter):
'''
Converts the database context to RSD inputs.
'''
......@@ -89,12 +109,12 @@ class RSD_DBContext(ILP_DBContext):
getters.extend(self.attribute_clause(table, att))
return '\n'.join(self.db_connection() + modeslist + getters + self.user_settings())
class Aleph_DBContext(ILP_DBContext):
class Aleph_Converter(ILP_Converter):
'''
Converts the database context to Aleph inputs.
'''
def __init__(self, *args, **kwargs):
ILP_DBContext.__init__(self, *args, **kwargs)
ILP_Converter.__init__(self, *args, **kwargs)
self.__pos_examples, self.__neg_examples = None, None
def __examples(self):
......@@ -141,14 +161,12 @@ class Aleph_DBContext(ILP_DBContext):
return '\n'.join(self.db_connection() + local_copies + self.user_settings() + modeslist + determinations + types + getters)
def concept_type_def(self, table):
#return ['%s(%s).' % (table, id) for (id,) in self.rows(table, [self.db.pkeys[table]])]
var_pk = self.db.pkeys[table].capitalize()
variables = ','.join([var_pk if col.capitalize() == var_pk else '_' for col in self.db.cols[table]])
return ['%s(%s) :-' % (table, var_pk),
'\t%s(%s).' % (table, variables)]
def constant_type_def(self, table, att):
# return ['%s(%s).' % (att, val) for val in self.db.col_vals[att]]
var_att = att.capitalize()
variables = ','.join([var_att if col == att else '_' for col in self.db.cols[table]])
return ['%s(%s) :-' % (att, var_att),
......@@ -165,6 +183,69 @@ class Aleph_DBContext(ILP_DBContext):
cols = ','.join([col.capitalize() for col in self.db.cols[table]])
return ':- repeat, tmp_%s(%s), (%s(%s), !, fail ; assertz(%s(%s)), fail).' % (table, cols, table, cols, table, cols)
class Orange_Converter(Converter):
'''
Converts the target table selected in the given context as an orange example table.
'''
continuous_types = ('FLOAT','DOUBLE','DECIMAL','NEWDECIMAL')
discrete_types = ('TINY','SHORT','LONG','LONGLONG','INT24','YEAR','VARCHAR','BIT','SET','VAR_STRING','STRING')
def __init__(self, *args, **kwargs):
Converter.__init__(self, *args, **kwargs)
self.types = self.fetch_types(self.db.target_table, self.db.cols[self.db.target_table])
def target_table(self):
'''
Returns the target table as an orange example table.
'''
import orange
from mysql.connector import FieldType
table, cls_att = self.db.target_table, self.db.target_att
cols = self.db.cols[table]
attributes, metas, classVar = [], [], None
for col in cols:
att_type = self.orng_type(col)
att_vals = self.db.col_vals[table][col]
if att_type == 'd':
att_var = orange.EnumVariable(str(col), values=[str(val) for val in att_vals])
elif att_type == 'c':
att_var = orange.FloatVariable(str(col))
else:
att_var = orange.StringVariable(str(col))
if col == cls_att:
if att_type == 'string':
raise Exception('Unsuitable data type for a target variable: %d' % att_type)
class_var = att_var
continue
elif att_type == 'string':
metas.append(att_var)
else:
attributes.append(att_var)
domain = orange.Domain(attributes + [class_var])
for meta in metas:
domain.addmeta(orange.newmetaid(), meta)
dataset = orange.ExampleTable(domain)
for row in self.rows(table, cols):
example = orange.Example(domain)
for col, val in zip(cols, row):
example[str(col)] = str(val)
dataset.append(example)
return dataset
def orng_type(self, col):
'''
Assigns a given mysql column an orange type.
'''
mysql_type = self.types[col]
n_vals = len(self.db.col_vals[self.db.target_table][col])
if mysql_type in Orange_Converter.continuous_types or (n_vals >= 50 and mysql_type in Orange_Converter.discrete_types):
return 'c'
elif mysql_type in Orange_Converter.discrete_types:
return 'd'
else:
return 'string'
if __name__ == '__main__':
from context import DBConnection, DBContext
......@@ -173,10 +254,12 @@ if __name__ == '__main__':
context.target_att = 'direction'
context.target_att_val = 'east'
rsd = RSD_DBContext(context)
ex, bk = rsd.all_examples(), rsd.background_knowledge()
# rsd = RSD_Converter(context)
# ex, bk = rsd.all_examples(), rsd.background_knowledge()
aleph = Aleph_DBContext(context)
print aleph.positive_examples()
print aleph.negative_examples()
print aleph.background_knowledge()
\ No newline at end of file
# aleph = Aleph_Converter(context)
# print aleph.positive_examples()
# print aleph.negative_examples()
# print aleph.background_knowledge()
orange = Orange_Converter(context)
orange.target_table()
\ No newline at end of file
......@@ -11,7 +11,9 @@ def mysql_db_context(request, input_dict, output_dict, widget):
con = input_dict['connection']
initial_context = DBContext(con)
initial_target_cols = initial_context.cols[initial_context.target_table]
initial_target_col_vals = initial_context.col_vals[initial_target_cols[0]]
initial_target_col_vals = initial_context.col_vals[initial_context.target_table][initial_target_cols[0]]
cols_dump = json.dumps(initial_context.cols)
col_vals_dump = json.dumps(initial_context.col_vals)
return render(request, 'interactions/db_context.html', {'widget':widget, 'context': initial_context, 'target_cols' : initial_target_cols, 'cols' : cols_dump, 'col_vals' : col_vals_dump, 'target_col_vals' : initial_target_col_vals})
......@@ -5,7 +5,7 @@ MySQL connectivity library.
'''
import mysql.connector as sql
from context import DBConnection, DBContext
from ilp_db_context import RSD_DBContext, Aleph_DBContext
from converters import RSD_Converter, Aleph_Converter, Orange_Converter
def mysql_connect(input_dict):
user = str(input_dict['user'])
......@@ -25,9 +25,17 @@ def mysql_db_context_finished(postdata, input_dict, output_dict):
return {'context' : context}
def mysql_rsd_converter(input_dict):
rsd = RSD_DBContext(input_dict['context'])
rsd = RSD_Converter(input_dict['context'])
return {'examples' : rsd.all_examples(), 'bk' : rsd.background_knowledge()}
def mysql_aleph_converter(input_dict):
aleph = Aleph_DBContext(input_dict['context'])
return {'pos_examples' : aleph.positive_examples(), 'neg_examples' : aleph.negative_examples(), 'bk' : aleph.background_knowledge()}
\ No newline at end of file
aleph = Aleph_Converter(input_dict['context'])
return {'pos_examples' : aleph.positive_examples(), 'neg_examples' : aleph.negative_examples(), 'bk' : aleph.background_knowledge()}
def mysql_query_to_odt(input_dict):
return {'dataset' : None}
def mysql_orange_converter(input_dict):
context = input_dict['context']
orange = Orange_Converter(context)
return {'dataset' : orange.target_table()}
......@@ -62,8 +62,9 @@
}
});
$('select[name="target_att{{widget.pk}}"]').change(function () {
var selected_table = $('select[name="target_table{{widget.pk}}"]').first('option:selected').val();
var selected_att = $(this).first('option:selected').val();
var available_vals = col_vals[selected_att];
var available_vals = col_vals[selected_table][selected_att];
// Change the list of options as the target attribute
var val_select = $('select[name="target_att_val{{widget.pk}}"]');
val_select.empty();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment