LoginSignup
1
0

More than 5 years have passed since last update.

英次郎の辞書データをOracleDBに挿入する part2

Last updated at Posted at 2017-07-17

始めに

英次郎の辞書データをOracleのテーブルに挿入した時の手順を記載します
今回は、前回作成したHTMLファイルから単語情報を抜き出し、DBにインサートするとこまで記載します

HTMLファイルの情報解析

やりたいこと

やりたいことを端的に書くと
1. Jsoupを使ってtrタグ要素に属するテキスト情報を取得する
2. 1.で取得したテキスト情報をQuerryRunnerのbatchメソッドで実行できる型(Object[])に変換する
3. 1.,2.で作成したList<Objects[]>のリストを1万件ずつinsertする
です

実装

WordInserter.java
package word;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jsoup.Jsoup;
import word.sql.WordDictionarySql;

public class WordInserter {

    private static String WORD_DICTIONARY =
            "C:/Users/*****/Desktop/puisan_102.txt";
    private static int LIMMIT = 10000;

    public static void main(String args[])throws Exception{
        long start = System.currentTimeMillis();
        System.out.println("List作成処理を開始します");
        List <Object[]>list =getDictionarySource()
                .stream().collect(Collectors.toList());
        long end = System.currentTimeMillis();
        System.out.println("List作成処理が完了しました");
        System.out.println(String.format("処理時間 %d秒",(end-start)/1000));

        start = System.currentTimeMillis();
        System.out.println("DB処理を開始します");
        OperateDB.createConnection();
        operateList(list);
        end = System.currentTimeMillis();
        System.out.println("DB作成処理が完了しました");
        System.out.println(String.format("処理時間 %d秒",(end-start)/1000));
        OperateDB.closeConnection();
    }

    //Jsoupを使ってHTMLタグを解析し、結果をリストにする関数
    public static List<Object[]> getDictionarySource(){
        try{
            return Jsoup.parse(new File(WORD_DICTIONARY),"UTF-8")
                    //タグ trに属する子要素をすべて取得する
                    .getElementsByTag("tr") 
                    .stream()
                    //タグ trに属する子要素のテキストを取得し、
                    //map関数を使ってDBにインサートできるデータ構造
                    //(この場合はObject[])に変換する
                    .map(s->new DictionaryWord(
                            s.getAllElements().eachText()).params)
                    //QueryLinnerのbatchでインサートできるようにList<Object[]>
                    //に集約する
                    .collect(Collectors.toList());
        }catch(Exception e){
            e.printStackTrace();
            return new ArrayList<Object[]>();
        }
    }

    //引数で渡されたListに対して、1万件単位でInsert処理を実行する
    public static void operateList(List<Object[]> word){
        Stream.iterate(1, s->s+1)
        .limit((int)Math.ceil(word.size()/LIMMIT))
        .forEach(i->executeSQL(word,i));
    }

    public static void executeSQL(List<Object[]>list,int from){
        if(list.size()<((from+1)*LIMMIT))
            WordDictionarySql.insertToWordDictionary(
                    list.subList(from*LIMMIT, list.size()));
        else 
            WordDictionarySql.insertToWordDictionary(
                    list.subList((from-1)*LIMMIT, from*LIMMIT));
    }

    public static class DictionaryWord{
        public long wordIndex;
        public int wordLevel;
        public String word;
        public String searchWord;
        public String meaning;
        public String shortVer;
        public Object[] params=new Object[6];

        public DictionaryWord(List<String>list){
            this.wordIndex = Long.parseLong(list.get(1));
            params[0] = this.wordIndex;
            this.wordLevel = Integer.parseInt(list.get(3).replaceAll("■", ""));
            params[1] = this.wordLevel;
            this.word = list.get(2);
            params[2] = this.word;
            this.searchWord = list.get(2).toLowerCase();
            params[3] = this.word;
            this.meaning = list.get(4);
            params[4] = this.meaning;
            this.shortVer = list.get(4).length()>1000?
                    list.get(4).substring(0,1000):list.get(4);
            params[5] = this.shortVer;
        }
        public String toString(){
            String format = "wordIndex=%d  wordLevel=%d "
                    + "word=%s meaning=%s shortVer=%s ";
            return String.format(format,this.wordIndex,this.wordLevel, 
                    this.word,this.meaning,this.shortVer);
        }
    }
}

雑感

Jsoupの解析結果として作られるDOMとJava8のStream関数の相性が良すぎてびっくりしてます
Stream関数がなければとてもじゃないけど、Javaで実装しようなんて思わなかったかも
(その場合は、rubyあたりを使っていたと思いますが)

DBへの挿入処理

やりたいこと

引数でもらったList<Ojbect[]>のlistを前回の記事で作ったOperateDB#insertに渡すだけです

実装

WordDictionarySql.java
package word.sql;

import java.util.List;
import word.OperateDB;

public class WordDictionarySql {

    public static String INSERT_SQL = "insert into WORD_DICTIONAY "
            + "(WORD_INDEX,WORD_LEVEL,WORD,SEARCH_WORD,MEANING,SHORT_VER) values(?,?,?,?,?,?)";

    public static void insertToWordDictionary(List<Object[]> word){
        try{
            OperateDB.insert(word,INSERT_SQL);
        }catch(Exception e){
            e.printStackTrace();
            throw new RuntimeException("DBのインサート処理でエラーが発生しました");
        }
    }
}

感想

約33万件のデータをOracleのテーブルに投入しましたが、実行時間は102秒程度でした
ちなみに,autocommitを有効にしている場合は、実行時間が230秒と倍程度かかっていました
autocommitを有効するとパフォーマンスが落ちる、ということを数字の上からも実感することができました

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0