Commit b33b27f8 authored by Christine Plumejeaud's avatar Christine Plumejeaud
Browse files

fix an error of GIT usage, forgive me

parent 8cdd0218
This diff is collapsed.
# Contrôles à faire sur navigocorpus
## Enumération des cas repérés comme erreurs
-----------------------------
```sql
SELECT documentary_unit_id, pointcall_uhgs_id,pointcall_indate, pointcall_outdate, *
FROM navigocheck.check_pointcall
WHERE ship_local_id = '0017223N'
ORDER BY pointcall_rank
```
***pointcall_uhgs_id non renseigné***
***le bateau fait une boucle mais pas de 'Z' dans le pointcall_function***
-----------------------------
***Dans la table check_pointcall les first name et last name sont inversés***
-----------------------------
```sql
SELECT pointcall_function, pointcall_rank, pointcall_indate, pointcall_outdate, documentary_unit_id, *
from navigocheck.check_pointcall
WHERE documentary_unit_id = '00125543'
ORDER BY pointcall_date
```
***pointcall_rank inversé***
-----------------------------
```sql
SELECT pointcall_function, pointcall_rank, documentary_unit_id, *
from navigocheck.check_pointcall
WHERE pointcall_function = 'A' and pointcall_rank != '1.0'
```
***rank >1 mais function 'A'***
-----------------------------
```sql
SELECT pointcall_rank,pointcall_uhgs_id,documentary_unit_id,*
FROM navigocheck.check_pointcall
WHERE pointcall_rank is null or documentary_unit_id is null
```
***Certains pointcall_rank sont null ou le documentary_unit_id est null mais pas le pointcall_rank -> 451 lignes***
-----------------------------
```sql
SELECT captain_local_id,*
from navigocheck.check_pointcall
WHERE char_length(captain_local_id) >8 --
```
***Local _id supérieur a 8 caractères dérangeant ?***
-----------------------------
***Il y a des entrées comme Portsmouth codées avec un UHGS_id qui n'a pas d'entrée dans Geo_general : B0000720***
```sql
select * from navigoviz.travel where id = 11184
--"B1965595";"B0000720"
select * from navigoviz.port_points
where uhgs_id in ('B1965595', 'B0000720')
--"B1965595" --> "Saint Pierre et Miquelon"
select * from navigoviz.port_points
where trim(lower(toponyme)) like 'portsm%th'
--portsmooth : "Portsmouth"
SELECT * FROM navigocheck.check_pointcall where ship_local_id = '0000532N'
--"Saint Pierre et Miquelon"
--"Portsmouth"
SELECT distinct pointcall_name, pointcall_uhgs_id , count(*)
FROM navigocheck.check_pointcall
where trim(lower(pointcall_name)) like 'portsmouth'
group by pointcall_name, pointcall_uhgs_id
----"Portsmouth";"A0385489";42 -- en angleterre, ok
--"Portsmouth";"B0000038";1 -- aux US, ok
--***"Portsmouth";"B0000720";5 # Erreur de geo-codage : aurait pu être codé A0385489***
--***"Portsmouth";"";16 # aurait pu être géocodé mais ne l'est pas ***
select * from navigoviz.port_points
where uhgs_id in ('A0385489', 'B0000038', 'B0000720')
```
-- ***B0000720 n'a pas d'entrée dans Geo_general *** (=port_points)
-----------------------------
***Certaine date sont mal renseignée***
- pointcall_date;pkid
> - 1787=02=06! ; 184489
> - 1787=07=03] ; 70863
> - 1787=11=24! ; 185089
> - 1792=02=11] ; 184137
> - 1795)08=21 ; 30235
> - 1795=03=28] ; 28020
> - 1795=11-23 ; 3663
> - 1796=04-16 ; 24807
-----------------------------
***Certain Ship_tonnage ont une syntaxe non documentées***
```
select ship_tonnage from navigo.pointcall group by ship_tonnage order by ship_tonnage;
```
- Notes :
> - ligne 1757 "acheté à Ostende"
> - ligne 1758 "nd"
> - ligne 1759 "null"
> - ligne 959 "0"
> - ligne 530 (405)[45]
> - ligne 552 (428 / 200)
> - ligne 558 (4300 Q)
> - ligne 585 (4575 Q)
> - ligne 1 ((((50)[150])))
> - ligne 2 ((((8)[18])))
> - ligne 3 (((71)))
> - ligne 5 ((113 (?)))
-----------------------------
***Cargo et dictionnaire des commodities***
Mail de Silvia du 6 mai 2019
---
*Pour clarifier les choses: nous insérons les produits comme dans les sources, puis nous attribuons un code-produit à l'item de la cargaison. Ce code_produit est lié à la table Dictonnary_commodity qu ielle comporte les traductions standardisés du produits, et le permanent_code
doc café, caffé, coffee et cafés se voient tous attribuer le même code (en l'occurrance, 00000138) (alors que café Moka a comme code 00000481)
ce code, sur Dictionnary_commodity, renvoie à la traduction dans plusieurs langues (et donc permet une recherche par plusieurs langues) et il est lié au permanent_coding (dans ce cas précis, trois permanent coding différents, mais qui commencenent tous par ID-GCC)
Voici ce que ça donne en termes de complétude:
le dictionnary comporte à ce jour 635 code_produit différents, dont 308 sont pourvus d'un permanent coding
Les congés de 1787 comportent un total de 21187 items, dont 21507 déjà pourvus d'un code. (il ne reste donc que les 600 derniers ajouts à coder et ça sera a priori assez vite fait) et 19557 pourvus d'un permanent code. C'est donc une bonne nouvelle car il ne reste pas grande chose à faire. Le b-mol est qu'il y a quelques erreurs de codage (si j'ai corrigé "riz" en "vin", je n'ai pas corrigé le code, ce qui fait qu'il reste lié à "rice" et au permanent_code du riz. )
Pour Marseille nous avons un total de 27000 item de cargaisons dont 22245 pourvus d'un code et 18792 d'un permanent_code.
Je vais pour ma part me charger de nettoyer les erreurs (je verrais avec Christine si elle peut me prémacher la tâche) et de coller l'identifiant du code là où cela manque (e me faisant expliquer par Jean-Pierre comment en créer de nouveaux si besoin pour des produits qu'on n'aurait jamais rencontré auparavant).
Le permanent_code et l'équivalent en anglais s'afficheront automatiquement dans la base Pointcall et Christine pourra l'utiliser pour les visualisations.
Il restera donc essentiellement à Pierrick à créer un permanent code (même sommaire, sans distinguer dans le détail) pour les produits codés qui n'en auraient pas. Si on le faisait sur toute la basa Navigo, a serait 325 produits à coder (635-308) , mais si on se limite dans un premier temps aux seuls codes présents dans G5+Marseille, ça sera nettement moins: pour les congés, nous avons un total de 234 codes, dont 164 déjà permacodés: il n'y a donc "que" 70 produits à permacoder
Pour Marseille, nous avons 352 codes de produits différents, dont 219 permacodés, donc il reste 133 produits à permacoder. Comme il y parfois les mêmes produits dans les deux listes, au total il y a environ 150 produits à permacoder.*
Liste les items prioritaires à permacoder dans le dictionnaire.
- missing_permanent_codings_....csv
Mais aussi, nous avons remarqué deux choses sur le dictionnaire :
- des **doublons de record_id** que nous avons corrigé à la main, en fluo dans le fichier Excel ci joint (le numero du record_id).
- des items dans **commodity_standardized de cargo** qu'on ne retrouve pas ni dans aucune des colonnes
Dictionary_french Dictionary_english
L' algo de contrôle vérifie
- commodity_purpose <=> commodity_standardized (donc il cherche d'abord dans la colonne en anglais du dictionnaire des commodities)
- commodity_id du dico ayant le commodity_standardized <=> commodity_id de cargo pour la ligne (et parfois çà ne matche pas)
- liste d'items (missing_items_....csv) qu'il faudrait vérifier et ou rajouter dans le dictionnaire des commodities
pour le reste, Clément est en train de coder qui détecte possiblement :
Flag 11 - 1) les incohérences entre commodity_purpose et commodity_standardized dans cargo (et les équivalent fr ou en du dictionnaire)
Flag 12 - 2) les incohérences entre commodity_standardized de cargo et commodity_id de cargo
Flag 13 - 3) les incohérences entre commodity_id de cargo et permanent_coding du dictionnaire
Flag 14 - 4) les incohérences entre commodity_permanent_coding de cargo et permanent_coding du dictionnaire
Pour ces entrées, TODO: listing des pointcall, et cargo correspondants.
Requetes SQL
```sql
select * from cargo where commodity_id = '00000011'
set search_path = 'navigo', 'navigocheck', 'navigoviz', 'public'
select count(*) from cargo c, pointcall p
where c.pointcall_id = p.record_id
and p.component_description__suite_id = '00000003'
and p.pointcall_date like '1787%'
and commodity_id is not null
select count(*) from cargo c, pointcall p
where c.pointcall_id = p.record_id
and p.component_description__suite_id = '00000003'
and p.pointcall_date like '1787%'
and commodity_permanent_coding is not null
select commodity_purpose, commodity_standardized, commodity_id, commodity_permanent_coding
from cargo c, pointcall p
where c.pointcall_id = p.record_id
and p.component_description__suite_id = '00000003'
and p.pointcall_date like '1787%'
and lower(commodity_purpose) like lower('Wine')
select distinct commodity_purpose, commodity_standardized, commodity_id, commodity_permanent_coding
from cargo c, pointcall p
where c.pointcall_id = p.record_id
and p.component_description__suite_id = '00000003'
and p.pointcall_date like '1787%'
and lower(commodity_purpose) like lower('vin')
create table navigo.dictionnary_commodity (
record_id text PRIMARY KEY,
dictionary_french text,
dictionary_english text,
permanent_coding text,
links_to_commodity text)
copy navigo.dictionnary_commodity from 'D:\CNRS\Travail_LIENSs\Projets\ANR_PORTIC\Data\cargo\dictionnaru commodities export.csv' WITH CSV HEADER DELIMITER ';'
copy navigo.dictionnary_commodity from '/home/plumegeo/navigo/ETL/data_07mai19/dictionnaru commodities export.csv' WITH CSV HEADER DELIMITER ';'
select commodity_purpose, commodity_standardized, commodity_id, commodity_permanent_coding
from navigocheck.check_cargo c
where commodity_standardized not in (select distinct dictionary_english from navigo.dictionnary_commodity )
select similarity('Oil (olive)', 'Olive oil')
--1
select similarity('Huile (olive)', 'Olive oil')
--0.4
select similarity('Wine (Bordeaux)', 'Bordeaux wine')
select similarity('Wine (Ceres)', 'Bordeaux wine')
-- toutes les entrées manquantes du dictionnaire
select commodity_standardized, max(similarity(commodity_standardized, dictionary_english))
from navigocheck.check_cargo c, navigo.dictionnary_commodity d
where c.commodity_standardized % dictionary_english
group by commodity_standardized
having max(similarity(commodity_standardized, dictionary_english)) < 1
-- select commodity_purpose, commodity_standardized, commodity_id, commodity_permanent_coding
-- from navigocheck.check_cargo c, navigo.dictionnary_commodity d
-- where similarity(commodity_standardized, dictionary_english) < 0.7
-- not in (select distinct dictionary_english from navigo.dictionnary_commodity )
select distinct flag1, flag2 from navigo_qualification
select count(distinct commodity_id) from navigocheck.check_cargo c where commodity_id is not null and commodity_permanent_coding is null
-- 186
```
# -*- coding: utf-8 -*-
'''
Created on 22 february 2019
@author: cplumejeaud
'''
# Comprendre les imports en Python : http://sametmax.com/les-imports-en-python/
# print sys.path
# sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))
## pour avoir le path d'un package
## print (psycopg2.__file__)
## C:\Users\cplume01\AppData\Local\Programs\Python\Python37-32\lib\site-packages\psycopg2\__init__.py
from __future__ import nested_scopes
import logging
import configparser
import xlsxwriter
import random
from xlrd import open_workbook, cellname, XL_CELL_TEXT, XL_CELL_DATE, XL_CELL_BLANK, XL_CELL_EMPTY, XL_CELL_NUMBER, \
xldate_as_tuple
from LoadFilemaker import LoadFilemaker
class Controls(object):
def __init__(self, config):
## Ouvrir le fichier de log
logging.basicConfig(filename=config.get('log', 'file'), level=int(config.get('log', 'level')), filemode='w')
self.logger = logging.getLogger('Controls')
self.logger.debug('log file for DEBUG')
self.logger.info('log file for INFO')
self.logger.warning('log file for WARNINGS')
self.logger.error('log file for ERROR')
self.loader = LoadFilemaker(config)
def do_the_job(self, config):
print("do checks")
def getCompletedOKdata(self, config, relation):
print("Build a data table for each field of the relation : nb filled, nb ok")
query = """SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE
TABLE_SCHEMA = 'navigo' and TABLE_NAME = '%s' order by ordinal_position""" % (relation)
rows = self.loader.select_sql(query)
cols = ", "
columns = []
for r in rows :
columns.append(r[0])
print (cols.join(columns))
rows = self.loader.select_sql("select count(pkid) from "+relation)
total = rows[0][0]
print ('total: ', total)
# Create a workbook and add a worksheet.
print(config['outputs']['file_name'])
workbook = xlsxwriter.Workbook(config['outputs']['file_name'])
worksheet = workbook.add_worksheet(relation)
filtre = config[relation]['filtre']
print('filtre: ', filtre)
# Start from the first cell. Rows and columns are zero indexed.
row = 0
col = 0
for c in columns :
#Nombre de lignes renseignées dans les sources G5 et Marseilles
query = """ select count(*) from %s where %s
and %s is not null """ % (relation, filtre, c)
rows = self.loader.select_sql(query)
completed = rows[0][0]
worksheet.write(row, col, c)
worksheet.write(row, col + 1, completed)
#Nombre d'erreurs null tant qu'on n'a pas fait les contrôles
query = """ select * from navigo.navigo_qualification where navigo_table = '%s' and navigo_field = '%s'
and flag1<>9 limit 1 """ % (relation, c)
erreurs = self.loader.select_sql(query)
if len(erreurs)>0:
query = """ select count(*) from navigo.navigo_qualification where navigo_table = '%s' and navigo_field = '%s' and flag1<>9""" % (relation, c)
rows = self.loader.select_sql(query)
errors = rows[0][0]
worksheet.write(row, col + 2, errors)
row += 1
workbook.close()
if __name__ == '__main__':
# Passer en parametre le nom du fichier de configuration
# configfile = sys.argv[1]
configfile = 'config_loadfilemaker.txt'
config = configparser.RawConfigParser()
config.read(configfile)
print("Fichier de LOGS : " + config.get('log', 'file'))
c = Controls(config)
c.do_the_job(config)
#c.getCompletedOKdata('geo_general')
#c.getCompletedOKdata(config, 'pointcall')
#c.getCompletedOKdata(config, 'cargo')
c.getCompletedOKdata(config, 'taxes')
c.loader.close_connection()
## pour le lancer sur le serveur
# nohup python3 Controls.py > out.txt &
# -*- coding: utf-8 -*-
'''
Created on 13 february 2019
@author: cplumejeaud
'''
# Comprendre les imports en Python : http://sametmax.com/les-imports-en-python/
# print sys.path
from __future__ import nested_scopes
import psycopg2
import logging
import configparser
from os import sys, path
import os, sys, traceback
import subprocess
import time
from stat import *
import random
from xlrd import open_workbook, cellname, XL_CELL_TEXT, XL_CELL_DATE, XL_CELL_BLANK, XL_CELL_EMPTY, XL_CELL_NUMBER, \
xldate_as_tuple
#pyopenxls à voir
## pour avoir le path d'un package
## print (psycopg2.__file__)
## C:\Users\cplume01\AppData\Local\Programs\Python\Python37-32\lib\site-packages\psycopg2\__init__.py
class LoadFilemaker(object):
def __init__(self, config):
## Ouvrir le fichier de log
logging.basicConfig(filename=config.get('log', 'file'), level=int(config.get('log', 'level')), filemode='w')
self.logger = logging.getLogger('LoadFilemaker (v1.1)')
self.logger.debug('log file for DEBUG')
self.logger.info('log file for INFO')
self.logger.warning('log file for WARNINGS')
self.logger.error('log file for ERROR')
## Open both a ssh connexion for copy/remove, and a tunnel for postgres connexion
self.postgresconn = self.open_connection(config)
def close_connection(self):
'''
Cleanly close DB connection
:param postgresconn:
:return:
'''
if self.postgresconn is not None:
self.postgresconn.close()
def open_connection(self, config):
'''
Open database connection with Postgres
:param config:
:return:
'''
''''''
putty = config.get('ssh', 'putty')
localport = config.get('base', 'port') # local port for Postgres : 8003
remoteport = config.get('ssh', 'postgres_port') # remote server port for Postgres : 5432
identityfile = config.get('ssh', 'ppk')
password = config.get('ssh', 'passwd')
user = config.get('ssh', 'user')
server = config.get('ssh', 'server')
# Start tunnel
# self.tunnel = self.createTunnel(putty, localport, remoteport, identityfile, password, user, server)
# Acceder aux parametres de configuration
host = config.get('base', 'host')
port = config.get('base', 'port')
dbname = config.get('base', 'dbname')
user = config.get('base', 'user')
password = config.get('base', 'password')
# schema = config.get('base', 'schema')
driverPostgres = 'host=' + host + ' port=' + port + ' user=' + user + ' dbname=' + dbname + ' password=' + password
self.logger.debug(driverPostgres)
conn = None
try:
conn = psycopg2.connect(driverPostgres)
except Exception as e:
self.logger.error("I am unable to connect to the database. " + str(e))
# Test DB
if conn is not None:
cur = conn.cursor()
cur.execute('select count(*) from pg_namespace')
result = cur.fetchone()
if result is None:
print('open_connection Failed to get count / use of database failed')
else:
print('open_connection Got database connexion : ' + str(result[0]))
else:
print('open_connection Failed to get database connexion')
return conn
def do_the_job(self, config):
self.logger.info('\n---------------------------- Processing Filemaker files ---------------------------- \n')
try:
'''
self.loadfile(config, 'geo_general')
self.create_uncertain_check_tables(config, 'geo_general')
self.populate_uncertain_check_tables(config, 'geo_general')
'''
self.loadfile(config, 'pointcall')
self.create_uncertain_check_tables(config, 'pointcall')
self.populate_uncertain_check_tables(config, 'pointcall')
#self.loadfile(config, 'acting_parties')
#self.loadfile(config, 'actions')
#self.loadfile(config, 'component_description')
self.loadfile(config, 'cargo')
self.create_uncertain_check_tables(config, 'cargo')
self.populate_uncertain_check_tables(config, 'cargo')
self.loadfile(config, 'taxes')
self.create_uncertain_check_tables(config, 'taxes')
self.populate_uncertain_check_tables(config, 'taxes')
#self.create_uncertain_check_tables(config, 'component_description')
#self.create_uncertain_check_tables(config, 'acting_parties')
#self.create_uncertain_check_tables(config, 'actions')
#self.populate_uncertain_check_tables(config, 'acting_parties')
#self.populate_uncertain_check_tables(config, 'actions')
#self.populate_uncertain_check_tables(config, 'component_description')
except Exception as e:
exc_type, exc_value, exc_traceback = sys.exc_info()
print(e)
print(repr(traceback.format_exception(exc_type, exc_value, exc_traceback)))
self.logger.error(e)
self.logger.error(e.message)
self.logger.info('\n---------------------------- END ---------------------------- \n')
self.close_connection()
def create_uncertain_check_tables(self, config, relation):
print('create_uncertain_check_tables ', relation)
sql_createtable = """SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='navigo' and TABLE_NAME = '%s' order by ordinal_position""" % (
relation)
self.logger.info(sql_createtable)
columns = self.select_sql(sql_createtable)
sql_createtable = """ CREATE TABLE navigocheck.uncertainity_""" + relation + """ ( """
for c in columns:
sql_createtable += c[0] + ' int,'
sql_createtable = sql_createtable[:-1]
sql_createtable += ");"
self.logger.info(sql_createtable)
sql_droptable = "drop table IF EXISTS navigocheck.uncertainity_" + relation + " cascade;"
self.execute_sql(sql_droptable)
self.execute_sql(sql_createtable)
sql_createtable = """ CREATE TABLE navigocheck.check_""" + relation + """ ( """
for c in columns:
if (c[0] == 'pkid') :
sql_createtable += c[0] + ' int,'
else :
sql_createtable += c[0] + ' text,'
sql_createtable = sql_createtable[:-1]
sql_createtable += ");"
self.logger.info(sql_createtable)
sql_droptable = "drop table IF EXISTS navigocheck.check_" + relation + " cascade;"
self.execute_sql(sql_droptable);
print(sql_droptable)
self.execute_sql(sql_createtable)
def populate_uncertain_check_tables(self, config, relation):
print('populate_uncertain_check_tables ', relation)
query = """SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='navigo' and TABLE_NAME = '%s' order by ordinal_position""" % (relation)
self.logger.info(query)
columns = self.select_sql(query);
sql_insert_head = "insert into navigocheck.uncertainity_" + relation + " ( select "
for c in columns:
if (c[0] == 'pkid'):
sql_insert_head += c[0] + ','
else:
sql_insert_head += ' (navigo.rm_parentheses_crochets('+c[0]+')).code ,'
sql_insert_head = sql_insert_head[:-1]
sql_insert_head += " from navigo." + relation+");"
self.logger.info("\n"+sql_insert_head+"\n")
self.execute_sql(sql_insert_head)
sql_insert_head = "insert into navigocheck.check_" + relation + " ( select "
for c in columns:
if (c[0] == 'pkid'):
sql_insert_head += c[0] + ','
else:
sql_insert_head += ' (navigo.rm_parentheses_crochets('+c[0]+')).value ,'
sql_insert_head = sql_insert_head[:-1]
sql_insert_head += " from navigo." + relation+");"
self.logger.info("\n"+sql_insert_head+"\n")
self.execute_sql(sql_insert_head)
def loadfile(self, config, relation):
print('Processing ' + relation)
print('Data are in: ' + config.get(relation, 'file_name'))
wb = open_workbook(config.get(relation, 'file_name'))
sheet = wb.sheet_by_name(config.get(relation, 'sheet_name'))
print("Lignes : ", sheet.nrows, "Colonnes : ", sheet.ncols)
## Traitement de la première ligne : creation de la relation
row = 0
sql_createtable = "create table navigo." + relation + " ( \n\t pkid serial primary key,"
sql_insert_head = "insert into navigo." + relation + " ( "
for col in range(0, sheet.ncols):
if sheet.cell(row, col).ctype is not XL_CELL_BLANK and sheet.cell(row, col).ctype is not XL_CELL_EMPTY:
self.logger.info(sheet.cell(row, col).value)
column_name = sheet.cell(row, col).value
if column_name.find("::") > -1:
column_name = column_name[:column_name.index("::")] + '__' + column_name[
column_name.index("::") + 2:]
sql_createtable += "\n\t" + column_name + " text,"
sql_insert_head += column_name + ","
else:
print("l'entête du fichier excel ne peut contenir des colonnes vides")
exit(0)