Jak zpracovat adresní místa RÚIAN ve formátu CSV

26.09.2022 Programování #programování #shell #mysql

Ukázka jak provést import dat z RÚAIN do MySQL. Pak s nimi lze pracovat jednodušeji např. při programování různých našeptávačů ulic a měst.


Při používání našeptávače adresy, lze využít oficiálních dat z katastru nemovitostí. NA stránce lze stáhnout ZIP soubor adresních míst. V zip souboru j přes 6000 souborů CSV, ve kterých jsou adresní místa podle krajů (asi). ZRuční zpracování takového množství souborů je prakticky nemožné. Zde je uveden postup, jak data naimportovat do databáze MySQL.

1. Převedení do UTF8

Soubory CSV jsou v latin1 a pokud se má s daty pracovat nějak rozumně, musí se překonvertovat do UTF8. Proto stažený ZIP soubor se rozbalí do nějaké složky. Následně se vytvoří podsložka utf a spustí se skript, který je ve stejné složce jako rozbalené originální CSV soubory:

#!/bin/sh

for file in *.csv; do
    iconv -f cp1250 <"$file" >"$file".tmp && mv "$file.tmp" utf/"$file"
done

 

Skript prochází všechny soubory CSV, převádí je do UTF8 a překonvertované ukládá do složky utf.

2. Import z CSV do MYSQL

V první řadě se musí vytvořit databáze s tabulkou, kam se budou data importovat.

--
-- Table structure for table `adresni_mista`
--

CREATE TABLE `adresni_mista` (
  `kod_adm` int(11) NOT NULL,
  `kod_obce` int(11) NOT NULL,
  `nazev_obce` text NOT NULL,
  `kod_momc` text NOT NULL,
  `nazev_momc` text NOT NULL,
  `kod_obvodu` text NOT NULL,
  `nazev_obvodu` text NOT NULL,
  `kod_casti_obce` text NOT NULL,
  `nazev_casti_obce` text NOT NULL,
  `kod_ulice` text NOT NULL,
  `nazev_ulice` text NOT NULL,
  `typ_so` text NOT NULL,
  `cislo_domovni` text NOT NULL,
  `cislo_orientacni` text NOT NULL,
  `znak_cisla_orientacniho` text NOT NULL,
  `psc` text NOT NULL,
  `souradnice_y` text NOT NULL,
  `souradnice_x` text NOT NULL,
  `plati_od` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 

Následně se spustí skript pro import:

#!/bin/bash

CESTA_K_CSV="/Volumes/DataHD/CSV/utf"         ## cesta k souborům
SEZNAM="/Volumes/DataHD/CSV/utf/seznam.txt"   ## dočasný soubor

######################
HOST="localhost"
USER="root"                 ## uživatel do DB
PASSWORD="1234"             ## heslo do DB
DB="mista"                  ## databaze
TABLE="adresni_mista"       ## tabulka v DB, kam se budou importovat data
######################

# smaže první řádek v každém souboru:
find $CESTA_K_CSV -type f -exec sed -i '' '1d' {} ;

# seznam souborů pro import
find $CESTA_K_CSV -type f > $SEZNAM

# import
while read line; do

     /Applications/MAMP/Library/bin/mysql $DB -e "LOAD DATA INFILE '$line' INTO TABLE $TABLE CHARACTER SET utf8 FIELDS TERMINATED BY ';'" -h $HOST -u $USER --password=$PASSWORD --local-infile=1

done < $SEZNAM

rm $SEZNAM;
exit;

 

Všechna data se převedou do tabulky v MySQL.

Spojení všech CSV souborů do jednoho

Lze také provést spojení všech CSV souborů do jediného CSV a s tím dále pracovat. Musí se brát, ale na vědomí, že soubor bude poměrně veliký s cca 2.9 miliony řádků.

#! /bin/bash

# Merge files to a single file
# Command structure:
# /bin/bash merge_files.sh -d directory_containing_input_files -p input_file_prefix -o output_file_name -r -l log_prefix
# Flags
# -d : (required) directory containing files
# -p : (optional) input file prefix | default - all files
# -o : (optional) output file name | default - 'output.txt'
# -s : (optional) start line of matching files | default - 1
# -f : (optional) start line of first matching file | default - 1
# -r : (optional) delete prefix files
# -l : (optional) log prefix
# Example:
# /bin/bash merge_files.sh -d scripts/historical_data_loader/sales/_outputs -p test -o abc.csv
#
# Above command merge all files with name starting as 'test'
# in 'scripts/historical_data_loader/sales/_outputs' directory
# and create a new file called 'abc.csv'
#

usage() {
  echo "/bin/bash merge_csv_files.sh -d directory_containing_input_files [-p input_file_prefix] [-o output_file_name] [-r] [-l]"
  echo "Flags"
  echo "-d : (required) directory containing files"
  echo "-p : (optional) input file prefix | default - all files"
  echo "-o : (optional) output file name | default - 'output.txt'"
  echo "-s : (optional) start line of matching files | default - 1"
  echo "-f : (optional) start line of first matching file | default - 1"
  echo "-r : (optional) delete prefix files"
  echo "-l : (optional) log prefix"
  exit 1
}
# FLAGS
output_file_name="output.txt"
delete_files=false
inp_prefix=""
log_prefix=""
file_start_line=1
while getopts "d:p:o:s:f:rl:" flag;
do
    case "${flag}" in
        d) file_dir=${OPTARG};;
        p) inp_prefix=${OPTARG};;
        o) output_file_name=${OPTARG};;
        s) file_start_line=${OPTARG};;
        f) first_file_start_line=${OPTARG};;
        r) delete_files=true;;
        l) log_prefix=${OPTARG};;
        *) usage;;
    esac
done

if [ -z "${first_file_start_line}" ]; then
  first_file_start_line=${file_start_line}
fi

echo "${log_prefix}log_prefix=${log_prefix}"
echo "${log_prefix}file_dir=${file_dir}"
echo "${log_prefix}inp_prefix=${inp_prefix}"
echo "${log_prefix}output_file_name=${output_file_name}"
echo "${log_prefix}delete_files=${delete_files}"

# VALIDATIONS
if [ -z "${file_dir}" ]; then
  echo "${log_prefix}ERROR: Directory containing input files should be passed with flag -d"
  exit 1
fi

if [ ! -d "${file_dir}" ]; then
  echo "${log_prefix}ERROR: No such directory : ${file_dir}"
  exit 1
fi

files=(${file_dir}/${inp_prefix}*)
if [ ! -f "${files[0]}" ]; then
  echo "${log_prefix}ERROR: Files not found!"
  echo "${log_prefix}DEBUG: Files: ${files[*]}"
  exit 1
fi

merge_dir="merged_${output_file_name}"
# CREATING DIRECTORY TO PUT TEMPORARY OUTPUT FILE
echo "${log_prefix}INFO: Creating new merged directory if not exist in ${file_dir}..."
mkdir -p ${file_dir}/${merge_dir}

echo "${log_prefix}Setting output file name as : $output_file_name"

# START FILE MERGING
echo "${log_prefix}INFO: Number of files to merged=${#files[@]}"
echo "${log_prefix}INFO: files=${files[*]}"
echo "${log_prefix}INFO: Copying first file ${files[0]} to the output file"
if [[ "${first_file_start_line}" -gt "1" ]];
then
  sed $(($first_file_start_line - 1))d ${files[0]} > ${file_dir}/${merge_dir}/${output_file_name}
else
  cp ${files[0]} ${file_dir}/${merge_dir}/${output_file_name}
fi
echo "${log_prefix}INFO: Copying data to the output file"
if [[ "${file_start_line}" -gt "1" ]];
then
  sed -r 1d "${files[@]:1}" >> ${file_dir}/${merge_dir}/${output_file_name}
else
  cat "${files[@]:1}" >> ${file_dir}/${merge_dir}/${output_file_name}
fi
echo "${log_prefix}INFO: Output file saved to merged"

if [ "${delete_files}" = true ]; then
  echo "${log_prefix}INFO: Removing files with prefix ${file_dir}/${inp_prefix}"
  rm ${file_dir}/${inp_prefix}*
  echo "${log_prefix}INFO: Removed files with prefix ${file_dir}/${inp_prefix}"
fi

echo "${log_prefix}INFO: Moving File to root directory"
mv ${file_dir}/${merge_dir}/${output_file_name} ${file_dir}/${output_file_name}
rm -R ${file_dir}/${merge_dir}
echo "${log_prefix}INFO: Output file saved to ${file_dir}/${output_file_name}"

Skript je uložen do souboru merge.sh. Volání probíhá:

merge.sh -d utf  -o '_result.csv'

Originál skript je k nahlédnutí na https://github.com/prabushitha/file-merge-script. Musel být upraven pro chybu v sed.

Ke stažení:

  1. Skript pro převod do utf8.
  2. Skript pro import do MySQL.
  3. Skript pro spojení všech CSV.