Newer
Older
osmCoverage / src / osm / jp / coverage / fuel / DbExist.java
@hayashi hayashi on 21 Mar 2018 12 KB 完成: Fuel
package osm.jp.coverage.fuel;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;
import jp.co.areaweb.tools.csv.CsvRecord;
import jp.co.areaweb.tools.database.*;
import org.hsqldb.HsqlException;
import osm.jp.api.Osmdb;

public class DbExist extends Osmdb {

    /** メイン
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception 
    {
        Connection hsqldb = null;
        try {
            // DB.tableを作成
            hsqldb = DatabaseTool.openDb("database");
            create(hsqldb);
            
            /**
             * 既存のOSMガソリンスタンドを読み込む
             * OSM OverPassAPI を使って、既存のGSデータを取得して、「HSQLDB.FUEL_EXIST」にSTOREする
             */
            (new DbExist()).getJapanCapabilities(hsqldb);
            
            
            DbExist.export(hsqldb);
        }
        finally {
            if (hsqldb != null) {
                DatabaseTool.closeDb(hsqldb);
            }
        }
    }
    
    /*
    Test data:
    ノード: エネオス (2015835273)  場所: 35.4367770, 139.4035710
    ノード: ENEOS (1769261234) 場所: 35.4330583, 139.4006876 brand=no
    ノード: 出光 (3877535257) 場所: 45.3985390, 141.6882450 brand=no
    
    select osm_id,amenity,brand,disused,name,
        ST_Y(ST_Transform(way,4326)) as lat,
        ST_X(ST_Transform(way,4326)) as lon
    from planet_osm_point
    where amenity='fuel';
    
    
    ウェイ: 出光 (161877397) ノード
                                1738352013
                                1738351984
                                1738352019
                                1738352024
                                1738352017
                                1738352013
    select osm_id,amenity,brand,name,way_area,
            ST_Astext(ST_Transform(way,4326)) ,
            ST_Y(ST_Transform(ST_Centroid(way),4326)) as lat,
            ST_X(ST_Transform(ST_Centroid(way),4326)) as lon
    from planet_osm_polygon 
    where amenity='fuel';
    
    161877397;"fuel";"出光";"出光";1415.14;"POLYGON((139.402982078119 35.4372453832977,139.403208992559 35.4373490207424,139.4033330499 35.4371591650393,139.403407160911 35.4370741177365,139.403148446109 35.4369273706731,139.402982078119 35.4372453832977))"
    ST_Centroid(way)
    
    */
    /**
     * 
     * <pre>{@code 
     *  (
     *    node[disused:amenity=fuel](35.42,139.39,35.45,139.42);
     *    way[amenity=fuel](35.42,139.39,35.45,139.42);
     *    node[amenity=fuel](35.42,139.39,35.45,139.42);
     *    (way[amenity=fuel](35.42,139.39,35.45,139.42);>;);
     *  );
     *  out;
     * }</pre>
     * 
     * <pre>{@code 
     *  select osm_id,amenity,brand,disused,name from planet_osm_point where amenity='fuel';
     * }</pre>
     *
     * <pre>{@code 
     *  select osm_id,amenity,brand,name,way_area,ST_Astext(ST_Transform(way,4326)) from planet_osm_polygon where amenity='fuel';
     * 
     * 168977587;"fuel";"JA";"兼城SS";1378;"POLYGON((127.692529751123 26.1483225993078,127.692852156479 26.1482644594179,127.692800683013 26.1478020809547,127.692690280065 26.1478324815483,127.692623984397 26.1480452048431,127.692529751123 26.1483225993078))"
     * 
     * 
     *  select id,nodes,tags from planet_osm_ways;
     * }</pre>
     * 
     * @param hsqldb
     * @throws Exception
     */
    public void getJapanCapabilities(Connection hsqldb) throws Exception {
        // 通常 → 50ポイント
        // BRANDなし → 1ポイント
        // FIXMEあり → 1ポイント
        readExisting(hsqldb, "where amenity='fuel'", POINT_NO_BRAND | POINT_FIXME);
        readExistingSub(hsqldb, "disused:amenity", "fuel", POINT_NO);
        readExistingSub(hsqldb, "abandoned:amenity", "fuel", POINT_NO);
        readExistingSub(hsqldb, "demolished:amenity", "fuel", POINT_NO);
        readExistingSub(hsqldb, "historic:amenity", "fuel", POINT_NO);
        readExistingSub(hsqldb, "was:amenity", "fuel", POINT_NO);
        readExistingSub(hsqldb, "removed:amenity", "fuel", POINT_NO);
        readExistingSub(hsqldb, "no:amenity", "fuel", POINT_NO);
    }
    
    /**
     * 'table.FUEL'の内容をCSV形式にして標準出力に出力する
     * @param hsqldb
     * @throws java.sql.SQLException
     */
    public static void export(Connection hsqldb) throws SQLException {
        String header = "idref,lat,lon,score";
        System.out.println("TABLE: "+ TABLE_NAME);
        System.out.println(header);
        PreparedStatement ps8 = hsqldb.prepareStatement("SELECT idref,lat,lon,score FROM "+ TABLE_NAME);
        try (ResultSet rset8 = ps8.executeQuery()) {
            while (rset8.next()) {
                String idcode = rset8.getString(1);
                Double lat = rset8.getDouble(2);
                Double lon = rset8.getDouble(3);
                int score = rset8.getInt(4);
                System.out.println("OSM: "+ idcode +","+ lat +","+ lon +","+ score);
            }
        }
    }

    /**
     * File(HttpPOST.EXIST_FILE)を読み取って、データベースに反映させる。<br>
     * その際に、OSMノードを評価し、scoreを算定する
     * 
     * @param hsqldb       反映先のデータベースコネクタ(HSQLDB)
     * @param sqlWhere  POI条件
     * @param point     評価ポイント[POINT_NO|POINT_BRAND|POINT_NAME] 1: 'brand'  2:'name'
     * @throws Exception              エラー
     */
    public void readExisting(Connection hsqldb, String sqlWhere, int point) throws Exception {
        Connection osmdb = null;
        long counter = 0L;
        try {
            osmdb =  DatabaseTool.openDb("osmdb");
            String sqlNode = "select osm_id,brand,disused,name,ST_Y(ST_Transform(way,4326)) as lat,ST_X(ST_Transform(way,4326)) as lon from planet_osm_point " + sqlWhere;
            PreparedStatement ps1 = osmdb.prepareStatement(sqlNode);
            try (ResultSet rset1 = ps1.executeQuery()) {
                while (rset1.next()) {
                    counter += importExistingNode(hsqldb, osmdb, rset1, point);
                }
            }
            String sqlArea = "select osm_id,brand,disused,name,ST_Y(ST_Transform(ST_Centroid(way),4326)) as lat,ST_X(ST_Transform(ST_Centroid(way),4326)) as lon from planet_osm_polygon " + sqlWhere;
            PreparedStatement ps2 = osmdb.prepareStatement(sqlArea);
            try (ResultSet rset2 = ps2.executeQuery()) {
                while (rset2.next()) {
                    counter += importExistingNode(hsqldb, osmdb, rset2, point);
                }
            }

            System.out.println("Exists Node count = " + counter);
        }
        finally {
            DatabaseTool.closeDb(osmdb);
        }
    }

    /**
     * 
     * SELECT 
        planet_osm_point.osm_id, 
        planet_osm_point.amenity, 
        planet_osm_point.brand, 
        planet_osm_nodes.id, 
        planet_osm_nodes.tags
      FROM 
        public.planet_osm_point, 
        public.planet_osm_nodes
      WHERE 
        planet_osm_point.osm_id = planet_osm_nodes.id and 'disused:amenity'=ANY(planet_osm_nodes.tags) and 'fuel'=ANY(planet_osm_nodes.tags);
     * 
     * @param hsqldb
     * @param kStr
     * @param vStr
     * @param point
     * @throws Exception 
     */
    public void readExistingSub(Connection hsqldb, String kStr, String vStr, int point) throws Exception {
        Connection osmdb = null;
        long counter = 0L;
        try {
            osmdb =  DatabaseTool.openDb("osmdb");
            String sqlSelect = "SELECT tags,id,ST_Y(ST_Transform(way,4326)) as lat,ST_X(ST_Transform(way,4326)) as lon";
            String sqlWhere = String.format("WHERE (osm_id=id AND '%s'=ANY(tags) AND '%s'=ANY(tags))", kStr, vStr);
            String sql = String.format("%s FROM planet_osm_point,planet_osm_nodes %s", sqlSelect, sqlWhere);
            System.out.println(sql);
            
            PreparedStatement ps1 = osmdb.prepareStatement(sql);
            try (ResultSet rset1 = ps1.executeQuery()) {
                while (rset1.next()) {
                    String tags = rset1.getString("tags");
                    String idref = rset1.getString("id");
                    String latStr = rset1.getString("lat");
                    String lonStr = rset1.getString("lon");
                    double lat = Double.valueOf(latStr);
                    double lon = Double.valueOf(lonStr);
                    int score = score(point, tags);
                    //counter += importExistingNode(hsqldb, osmdb, rset1, point);
                    counter += insertExistingNode(hsqldb, idref, lat, lon, score, "");
                }
            }
            System.out.println("Exists Node count = " + counter);
        }
        finally {
            DatabaseTool.closeDb(osmdb);
        }
    }
    
    int score(int point, String tags) {
        int score = 50;
        if (tags == null) {
            return score;
        }
        
        boolean brandYes = false;
        boolean busYes = false;
        boolean fixmeYes = false;
        boolean nameYes = false;
        
        tags = tags.substring(1);
        tags = tags.substring(0, tags.length()-1);
        CsvRecord csv = new CsvRecord();
        csv.analizeRecord(tags);

        boolean key = true;
        boolean bus = false;
        for (String str : csv) {
            if (key) {
                if (str.startsWith("fixme")) {
                    fixmeYes = true;
                }
                else if (str.equals("bus")) {
                    bus = true;
                }
                else if (str.equals("brand")) {
                    brandYes = true;
                }
                else if (str.startsWith("name")) {
                    nameYes = true;
                }
                key = false;
            }
            else {
                if (bus) {
                    if (str.equals("yes")) {
                        busYes = true;
                    }
                    bus = false;
                }
                key = true;
            }
        }
        
        if (((point & POINT_NO_BRAND) != 0) && !brandYes) {
            score = 1;
        }
        if (((point & POINT_NO_NAME) != 0) && !nameYes) {
            score = 1;
        }
        if (((point & POINT_FIXME) != 0) && fixmeYes) {
            score = 1;
        }
        if (((point & POINT_BUS_NO) != 0) && !busYes) {
            score = 0;
        }
        return score;
    }
    

    /**
     * 
     * @param hsqldb
     * @param idref
     * @param lat
     * @param lon
     * @param score
     * @param name
     * @return
     * @throws IOException
     * @throws SQLException 
     */
    public int insertExistingNode(Connection hsqldb, String idref, double lat, double lon, int score, String name) throws IOException, SQLException {
        // idref と brandStr をデータベースに格納する
        String sql = String.format("INSERT INTO %s (idref,lat,lon,score,name) VALUES (%s,%2.7f,%3.7f,%d,%s)", 
                TABLE_NAME, 
                idref, lat, lon, score, name);
        System.out.println(sql);
        sql = String.format("INSERT INTO %s (idref,lat,lon,score,name) VALUES (?,?,?,?,?)", TABLE_NAME);
        try (PreparedStatement ps5 = hsqldb.prepareStatement(sql)) {
            ps5.setString(1, idref);
            ps5.setDouble(2, lat);
            ps5.setDouble(3, lon);
            ps5.setInt(4, score);
            ps5.setString(5, name);
            ps5.executeUpdate();
            return 1;
        }
        catch (HsqlException | SQLIntegrityConstraintViolationException e) {
            // integrity constraint violation: unique constraint or index violation; SYS_PK_10069 table: FUEL_EXIST
            // [HsqlException]は、無視する
            // integrity constraint violation: unique constraint or index violation; SYS_PK_10069 table: FUEL_EXIST
            // [SQLIntegrityConstraintViolationException]は、無視する
        }
        return 0;
    }
}