Believe you can

If you can dream it, you can do it.

全文検索システムを作りたい〜構想編〜

こんにちは、GWが始まって10連休の方も多いのではないでしょうか。
転職したばかりとはいえ、有給が付与されているのでお休みも取れるのですがカレンダー通りです。

先週からWEB+DB PRESSやSoftware Designといった雑誌を紙で購入しているのですが、本棚にびっしり配置されていてだいぶ場所が取られてしまっています。自宅にある設備で自炊が可能なのではと思い、調べてみたらスキャンを1ページ1ページ自分で行えばPDFを作ることが可能とわかったので自炊を始めています。

ただただPDFを作るだけでもいいのですが、せっかくなら全文検索できるようにして必要な情報にアクセスしやすいようにしたいと考えています。
ということで、システム構築みに向けて色々検討してみます。

要件

全文検索が行えること

ほしい情報やキーワードで調べることができないとせっかく電子化した意味はないかなと考えています。なので、全文検索が行えることが必須条件となります。

WEBシステムであること

全文検索が入ることで必然的にWEBシステムというのも必須条件となっていきますかね。

コストはかけない

僕はお小遣い制です。結婚してからビタ一文もお小遣いが上がっていないのでできる限りコストは抑えることとします。

出先でも利用できること

出先でも利用できることを目標としたい。必須としないのは「コストをかけない」が難しくなるからです。費用対効果を見ながら検討していきます。

実現方法

自作でシステム構築

勉強も兼ねて自力でシステムを構築している方法。
ほしい機能や仕組みを実現できる反面、いつ出来上がるか全く予想できないので計画が頓挫してしまう恐れがある。

なんらかのOSSを利用する

全文検索OSSで提供しているものを利用する方法。
ほしい機能や仕組みがあるかは運次第になってしまうものの、すぐにでもサービスを立ち上げることが可能になる。

結論

悩むこともなく「なんらかのOSSを利用する」で進んでみようと思います。思い浮かぶのはFESSぐらいなので、他に何があるのか調査からしていくことにします。オススメのOSSがあればコメントください。

3/19(土) 日報

3/19(土)の日報です。土日祝は休んでもいい気がしたが、せっかくなので続けてみる
日報はnoteにしようか悩み中

起床

  • いつも通りサプリ摂取
  • コーヒー飲みつつ洗濯物
  • ダラダラ

レーニングから昼食まで

  • 腹筋ローラー20回3セット
  • フィットネスバイク30分
  • 前職の上司から欲しいものリストのコカコーラゼロが届く!あざます!!
  • オイコスで朝食
  • ダラダラ
  • ちょっと読書

昼食から夕食まで

  • いつもと変わらない昼食(オートミール
  • ダラダラ
  • 買い物へ
  • 洗濯物取り込み
  • 夕食

夕食から就寝

  • 洗い物
  • TV見ながら団らん
  • ちょっと読書
  • 風呂

明日の予定&やりたいこと

  • [重要]執筆作業
  • 読書
  • SmartHRに入社情報入力
  • バリカン(坊主)
  • バイク自賠責加入とバッテリー用意
  • 服買いに行きたい

3/18(木) 日報

3/18(金)の日報
冬に戻ったような天気で寒い。。お休みも残り2週間で進捗が滞っていてヤバいな
次男が車の運転を披露してくれないので4月から通学できるのか心配だ。。

起床

  • マンガアプリを読む
  • 雇用時受入健康診断の受診
  • 住民票を貰いに支所へ

運動

  • スクワット:120回
  • フィットネスバイク:30分
  • オイコスで朝食

昼食から夕方

  • 執筆原稿の赤入れdone
  • 入社時のティータイムセットの住所入力
  • ちょっと読書
  • 昼食
  • 洗い物
  • ボケーと過ごす
  • 入社前面談
  • 娘を塾へ送迎
  • SmartHRに入力
    • 扶養部分がわからず。。総務に追加質問

夕食から就寝

  • 夕食
  • 洗い物
  • ボケーと過ごす
  • 執筆作業

明日の予定&やりたいこと

3/17(木) 日報

3/17(木)の日報です。
昨日に比べてちょっと肌寒い。。

起床

  • サプリを摂りつつ、コーヒーを落とす
  • ゴミ捨て
  • マンガアプリを読む
  • コーヒーを飲みつつ洗濯物を干す
  • ボケーとする

運動

  • 腕立て伏せ:15回ぐらい
  • 膝立ちの腕立て伏せ:10回4セット
  • フィットネスバイク:30分
  • オイコスで朝食

昼食・ダラダラ

  • 妻はお友だちとランチにお出かけ
  • コンビニへ買い物
  • 読書
  • ブログ
  • ダラダラ
  • 車の運転練習(次男)
  • 散歩がてらダイソーで買い物
  • 洗濯物取り入れ
  • 執筆赤入れ

夕食から就寝

  • 上田に酒井さんが来てると聞くがさすがに行けぬ。。

  • 夕食
  • 洗い物
  • 娘に背中を踏んでもらう
  • 星街すいせいの配信見る
  • 執筆赤入れ
    • 終わらず。。。
  • 風呂
  • SmartHRに入社情報入力
    • 終わらず。。。

明日の予定&やりたいこと

明日はちょっと忙しいかな

  • [重要]健康診断
  • [重要]入社前面談
  • [重要]住民票入手
  • [重要]執筆作業
  • [重要]SmartHRに入社情報入力
  • 読書
  • バリカン(坊主)
  • バイク自賠責加入とバッテリー用意
  • 服買いに行きたい

サーバサイドKotlinでKomapperを使ってみよう

Kotlin製ORマッパーのKomapperが5月に1.0のリリースされると聞いてSpringBoot上で試してみました。といってもサンプルソースも豊富なのでそれに毛が生えた程度です。。

CRUD

H2を利用してpersonテーブルを用意してCRUDを動かします。

create table person
(
    id    int GENERATED ALWAYS AS IDENTITY (START WITH 3) PRIMARY KEY,
    name  varchar(255) not null,
    email varchar(255) not null
);

エンティティ、マッピング定義

テーブルと対になるエンティティとPKなどの項目にアノテーションを定義して項目マッピングを行います。

data class Person(
    val id: Int? = null,
    val name: String,
    val email: String,
)

@KomapperEntityDef(Person::class)
data class PersonDef(
    @KomapperId
    @KomapperAutoIncrement
    val id: Nothing,
)

クエリ実行

QueryDSLを利用してSQLを実行します。メソッドチェーンでやりたいことをつなげていく感じなので直感的でわかりやすいですね。

@Service
class PersonService(
    private val database: JdbcDatabase
    ) {
    fun findAll(): List<Person> {
        return database.runQuery {
            val p = Meta.person
            QueryDsl.from(p).orderBy(p.id)
        }
    }

    fun findById(id: Int): Person {
        return database.runQuery {
            val p = Meta.person
            QueryDsl.from(p).where{ p.id eq id }.first()
        }
    }

    @Transactional
    fun insert(name: String, email: String): Person {
        return database.runQuery {
            val person = Person(name = name, email = email)
            val p = Meta.person
            QueryDsl.insert(p).single(person)
        }
    }

    @Transactional
    fun update(id: Int, name: String, email: String): Person {
        return database.runQuery {
            val person = findById(id)
            val p = Meta.person
            QueryDsl.update(p).single(person.copy(name = name, email = email))
        }
    }

    @Transactional
    fun delete(id: Int) {
        database.runQuery {
            val person = findById(id)
            val p = Meta.person
            QueryDsl.delete(p).single(person)
        }
    }
}

結合

テーブル結合をしたSQLも試してみます。チームテーブル、チームメンバーテーブルを用意して、personテーブルを含めた3テーブルの結合を行います。
DDLは次の通りです。

create table team
(
    id   int GENERATED ALWAYS AS IDENTITY (START WITH 3) PRIMARY KEY,
    name varchar(255) not null
);

create table team_member
(
    id        int GENERATED ALWAYS AS IDENTITY (START WITH 4) PRIMARY KEY,
    team_id  int not null,
    member_id int not null
);

エンティティとマッピング

data class Team(
    val id: Int? = null,
    val name: String,
)

@KomapperEntityDef(Team::class)
data class TeamDef(
    @KomapperId
    @KomapperAutoIncrement
    val id: Nothing,
)

data class TeamMember(
    val id: Int? = null,
    val teamId: Int,
    val memberId: Int,
)

@KomapperEntityDef(TeamMember::class)
data class TeamMemberDef(
    @KomapperId
    @KomapperAutoIncrement
    val id: Nothing,
)

left joinを行います。leftJoinメソッドで結合するテーブルを指定し、selectメソッドで取得するカラムを指定します。

@Service
class TeamService(
    private val database: JdbcDatabase
) {
    fun findById(id: Int): TeamDTO? {
        val g = Meta.team
        val m = Meta.teamMember
        val p = Meta.person
        val result = database.runQuery {
            QueryDsl.from(g)
                .leftJoin(m) { g.id eq m.teamId }
                .leftJoin(p) { m.memberId eq p.id }
                .where { g.id eq id }
                .orderBy(m.id)
                .select(g.id, g.name, p.id, p.name, p.email)
        }

        val members = result.map {
            Member(it[p.id]!!, it[p.name]!!, it[p.email]!!)
        }
        val member = result.first()
        val id = member[g.id]
        val name = member[g.name]

        return TeamDTO(id!!, name!!, members)
    }
}

完成したソースは↓です。

github.com

感想

SQLをメソッドチェーンで組み立てていくことができるので悩まずに実装できるのがいいですね。アノテーションプロセッサーを利用しているのでMetaで指定できるテーブルはコンパイルをしていないと怒られてしまうのは注意が必要です。(大した問題ではないが)

R2DBCに対応しているORマッパーは少ないので採用候補に上がるプロジェクトも多いんじゃないでしょうか。
基本機能を試した程度ですが、これから採用実績は増えていくこと間違いなしだと思います!!

3/16(水) 日報

3月末までは充電期間のためお休みをいただいております。
就業までの間にお休みをいただく(有給消化的な)のは初めてで、ダラけた生活を送ってしまっているので日報を書くことでダラけない生活を送る努力をしてみようと思い、今日から日報を書いていこうと思います。

興味ないと思いますが、お付き合いいただければです <( )>

起床

  • サプリを摂りつつ、コーヒーを落とす
  • マンガアプリを読む
  • コーヒーを飲みつつ洗濯物を干す
  • ボケーとする

運動

  • 腹筋ローラー:20回を3セット
  • フィットネスバイク:30分
  • オイコスで朝食

昼食

  • 早めの昼食
  • 洗い物など

お出かけ

  • 妻を送迎
  • 娘とダラダラお出かけ
    • ペットショップはしご
    • アポ無しで実家に行く
    • 善光寺のすみっコぐらし堂でお買い物

  • 図書館でブラブラ
  • 妻のお迎え

帰宅〜夕食

  • 洗濯物取り入れ
  • 息子のお迎え
  • ボケーとする
  • 夕食

寝るまで

  • ブログ書く
  • 洗い物など
  • YouTubeライブの勉強会参加
  • Spring Boot+Kotlin+Komapperのサンプル実装
  • 風呂

明日やりたいこと

  • [重要]本の執筆
  • 読書
  • バリカン(坊主)
  • バイク自賠責加入とバッテリー用意
  • 服買いに行きたい

退職しました

退職エントリが盛り上がっていましたが、自分も退職エントリです。
2/25を最終出社日、3/31をもって2年11ヶ月勤めた会社を退社することになりました。現在は有給消化というか特別休暇扱いで充電期間です。

なんで転職?

Twitter上でカジュアル面談受けているとか言っていたので、察していた方もいたかと思いますが、会社も僕自身としても不本意な結果となってしまったかなと思っています(そうであってほしいな)。
詳しい理由をこの場で語らないので、読んでくださってる方からすればもどかしい感じになってしまいますが、気になる・知りたいという方はご飯でも誘ってください。

会社や開発部・プロダクトが嫌になったとか、現職との人間関係がよくないといった理由ではないことは明言しておきます。個人的にはR&D部門に異動になりこれからといった気持ちでしたし、上司・同僚、他部門の皆様も素晴らしいメンバーでいい環境で働けていたと思っています。

現職への感謝

所属していた約3年間はとても楽しく刺激的で濃厚な経験させていただきました。
挑戦を許してくれる組織の中でときにはわがままを聞いていただき、たくさんの挑戦とサポートをしてくれたCTOやEM、同僚には感謝しかありません。またその結果、負債となるものも残してしまい申し訳なく思っております。。

転職活動

過去の転職はリファラルやTwitterナンパで比較的苦労せずに転職をしてきました。今回は転職サイト経由でカジュアル面談を受け、面談→応募→面接という正規の流れを行う転職活動でした。次の就業先を急いで探す必要があったものの、エージェントへの登録はなんとなくという理由で行いませんでした。

利用した転職サイトは経歴書のインポートができたFindlyとLAPRASがメインでWantedlyやForkwellを後から増やした感じで声がけを待ちつつ、こちらからもアプローチしていった感じで動きました。
声をかけていただいた企業でプロダクトや開発体制に興味を感じたらカジュアル面談をさせていただく形をとっていました。お時間をいただいた企業様には感謝しており、また僕のことを評価していただき応募してほしいと言っていただいたことはとても嬉しいお声で救われました。

ただ、今回の転職は急なこともあり家族にもだいぶ心配をかけてしまったため、家族の声を優先した結果、スタートアップフィルターをかけざるを得ませんでした。そのフィルターが発動したために応募しないという決断を行ったこともあり、親身になってくれた企業様や担当者様には大変申し訳なく思っております。

今後は?

4月からはECサイトを運営する企業でJavaエンジニアとしてフルリモートで働く予定です。
応募した理由はカルチャーフィットを感じたのと、担当予定業務に関わることでサービス・ビジネスの成長を感じたいと考えたためです。
入社まで残り数週間、色々な不安と期待を感じつつテックブログを読み込んだりmeetup動画を見て勉強とモチベーションアップをしていこうと思います。

最後に退職エントリには欲しいものリストもセットと聞いたので作ってみました(これでいいのかな?)。

www.amazon.jp