package models; import com.google.common.base.Strings; import models.word.BeginWord; import models.word.Relation; import models.word.RelationQueries; import org.h2.jdbcx.JdbcConnectionPool; import org.skife.jdbi.v2.DBI; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; import java.util.concurrent.atomic.AtomicReference; public class Database { private static Logger log = LoggerFactory.getLogger(Database.class); private static int MAX_PERIOD = 2; private static int MIN_WORD_COUNT = 3; private static AtomicReference<JdbcConnectionPool> ds = new AtomicReference<>(); /** * データベースの初期化 */ public static void initialize() { log.info("database initialize."); ds.set(createConnection()); final DBI dbi = new DBI(ds.get()); final RelationQueries relation = dbi.open(RelationQueries.class); relation.createRelationTable(); relation.close(); final BeginWord beginWord = dbi.open(BeginWord.class); beginWord.createBeginWordTable(); beginWord.close(); log.info("database initialized."); } public static void dispose() { ds.get().dispose(); } /** * 引数sentenceを解析し、文言にわけて、記録する */ public static void study(final String sentence) { log.info("study start. sentence: " + sentence); final String[] lines = WordAnalyzer.splitBySpecialSymbol(sentence); try { for (final String line : lines) { // 文章を解析して、単語ごとにスペースで区切る if (!Strings.isNullOrEmpty(line)) { // note: lineがnull,空文字の時は学習しない final List<String> words = WordAnalyzer.analyze(line); String preWord = null; int count = 1; for (final String word : words) { if (count == 1) { if (!isExistBeginWord(word, ds.get())) { insertBeginWord(word, ds.get()); } } else { final boolean isLast = (words.size() == count); if (!isExistRelation(preWord, word, isLast, ds.get())) { insertRelation(preWord, word, isLast, ds.get()); } } ++count; preWord = word; } } } log.info("study end"); } finally { //ds.dispose(); } } /** * 発言内容を生成する */ public static String pickSentence() { log.info("pickSentence start"); String words = ""; int periodCount = 0; int loopCount = 0; try { while (true) { // はじめの言葉を取得 words += selectBeginWord(ds.get()); String word = words; // 文言が英数記号のみならスペース追加 if (WordAnalyzer.isAllHalfNumericAndSymbols(words)) { words += " "; } int wordCount = 1; for (int i = 0; i < 15; ++i) { final Relation relation = selectRelation(word, ds.get()); if (relation == null) { periodCount += MAX_PERIOD; break; } final String nextWord = relation.followWord; word = relation.followWord; if (WordAnalyzer.isContainsPeriodWord(word)) ++periodCount; words += nextWord; ++wordCount; if (periodCount >= MAX_PERIOD) break; } if (periodCount >= MAX_PERIOD) break; if (wordCount < MIN_WORD_COUNT || loopCount < 5) { words = ""; ++loopCount; } else { break; } } // 半角英数字のみは許さない if (WordAnalyzer.isAllHalfNumericAndSymbols(words)) { return pickSentence(); } else { log.info("pickSentence end"); return words; } } finally { //ds.dispose(); } } /** * データベースへの接続を確立する */ private static JdbcConnectionPool createConnection() { final ConfigReader reader = ConfigReader.getInstance(); return JdbcConnectionPool.create(reader.getDatabaseURI(), reader.getDatabaseId(), reader.getDatabasePassword()); } /** * begin wordテーブルにすでに入っている文字か調べる */ private static boolean isExistBeginWord(final String word, final JdbcConnectionPool ds) { final DBI dbi = new DBI(ds); final BeginWord beginWord = dbi.open(BeginWord.class); final int result = beginWord.beginWordCount(word); beginWord.close(); return result > 0; } /** * begin wordテーブルに挿入する */ private static void insertBeginWord(final String word, final JdbcConnectionPool ds) { final DBI dbi = new DBI(ds); final BeginWord beginWord = dbi.open(BeginWord.class); beginWord.beginWordInsert(word); beginWord.close(); } /** * 最初の言葉を取得する */ private static String selectBeginWord(final JdbcConnectionPool ds) { final DBI dbi = new DBI(ds); final BeginWord beginWord = dbi.open(BeginWord.class); final String result = beginWord.beginWordSelectByRandom(); beginWord.close(); return result; } /** * Relationテーブルにすでに入っている文字か調べる */ private static boolean isExistRelation(final String leadWord, final String followWord, final boolean isLast, final JdbcConnectionPool ds) { final DBI dbi = new DBI(ds); final RelationQueries relation = dbi.open(RelationQueries.class); final boolean result = relation.relationGetOrNull(leadWord, followWord, isLast) != null; relation.close(); return result; } /** * Relationテーブルに挿入する */ private static void insertRelation(final String leadWord, final String followWord, final boolean isLast, final JdbcConnectionPool ds) { final DBI dbi = new DBI(ds); final RelationQueries relation = dbi.open(RelationQueries.class); relation.relationInsert(leadWord, followWord, isLast); relation.close(); } /** * 続きの言葉を取得する */ private static Relation selectRelation(final String leadWord, final JdbcConnectionPool ds) { final DBI dbi = new DBI(ds); final RelationQueries relation = dbi.open(RelationQueries.class); final Relation result = relation.relationSelectByRandom(leadWord); relation.close(); return result; } }