プロジェクト紹介
- NewCodesは企業技術ブログのキュレーションサービス
- Spring Boot + PostgreSQLアーキテクチャ
- 検索語オートコンプリート機能を実装: Termベースの推薦、子音・母音分解検索、初声検索、企業ページ推薦
パフォーマンス問題の発見
- Termテーブルに11万件のデータが蓄積
- API応答時間が1000ms以上に増加
- 目標: 100ms以内の応答
1回目の試み: インデックス追加 (1000ms → 700ms)
varchar_pattern_opsを使ったLIKE前方一致検索最適化インデックスを作成
CONCURRENTLYオプションでサービス停止なしにインデックスを作成
- term、decomposed_term、chosungカラムにそれぞれインデックスを適用
2回目の試み: LOWER関数インデックス (700ms → 110ms)
LOWER()関数の使用によるフルスキャン問題を発見
- 関数ベースインデックス(Functional Index)を作成
LOWER(カラム名) varchar_pattern_ops形式でインデックスを再構成
3回目の試み: JOIN → EXISTS (110ms → 100ms)
- CorporationとArticleのINNER JOINが性能ボトルネック
- EXISTSサブクエリに変更してスキャン範囲を縮小
- 「データの存在有無」だけを確認するよう最適化
4回目の試み: 非正規化 & カバリングインデックス (100ms → 90ms)
total_frequencyカラム追加で集計演算を除去
- GROUP BY、SUM演算を事前計算済みの値に置き換え
- カバリングインデックスでI/O回数を削減
INCLUDE句でtermとtotal_frequencyをインデックスに含める
5回目の試み: JDBC Template (90ms → 80ms)
- JPA/Hibernateのオーバーヘッドを除去
- JDBC Templateでクエリを直接実行
- 単純な参照ではORMレイヤーの省略が効果的
Nginx Rate Limiting問題の解決
- 初期設定: 1秒に2回制限、burst 10
- 100msデバウンシングによりリクエスト失敗が発生
- 改善: 1秒に10回許可、burst 20に変更
- 444 → 429 status codeに変更
応答データサイズの縮小
- JSONフィールド名を削除し、配列ベースの応答に変更
- 型を数値で区別 (0: Corporation, 1: Theme, 2: Term)
- ネットワーク転送時間を削減
CompletableFuture並列処理
- Corporation、Theme、Termの参照を独立して同時実行
- 逐次実行と比べて最大応答時間分だけで完了
- ExecutorServiceと例外処理を追加
最終成果
- 初期1000ms → 最終80ms (開発サーバー)、40ms (本番サーバー)
- 約90%以上の性能改善
主な学び
- 問題定義と方向性設定の重要性
- AI活用と開発者によるレビューのバランス
- 全体アーキテクチャ視点での設計の必要性
- インデックス種類の選択: 単一/複合/カバリングインデックス
- 関数使用時のインデックス無効化に注意
- JPA内部動作への理解
- EXPLAINによるクエリ実行計画分析
今後の改善方向
- Trieデータ構造の使用
- よく検索される用語のキャッシュ
- CDN活用 (グローバルサービス時)
27件のコメント
運営者です。
現在、コメントでの議論が投稿の技術的な内容とは関係のない部分まで複合的に絡み合い、過熱している様子が見られるため、ご案内いたします。
技術的な議論とフィードバックはいつでも歓迎します。
意見はさまざまであり得ますが、コメントを書く際には相手に対する基本的な礼儀を守り、論理を中心とした議論をお願いいたします。また、個人や経歴よりも、現在の投稿内容そのものを中心に議論していただければと思います。
サイト利用方法 のコメント投稿ガイドを、あらためてご確認ください。
なお、フラグされた投稿については、すでに記録およびシステム上の対応を行っており、関連する運営ポリシーとシステムは継続的に改善してまいります。
また、運営に関するご意見やフィードバックがありましたら、お気軽にメールでお問い合わせください。
はい、承知しました。
コメント欄の雰囲気が少し変だと思います。もしかして、最初に投稿されたときと比べてタイトルや内容が変わったのでしょうか? この程度の記事が投稿されること自体を、おかしいとは思いません。
「企業の技術ブログにこういう記事は書かないでしょう」といった意見もありますが、目標性能を定義し、それを達成するために改善を繰り返すことは、企業の技術ブログでもしばしば取り上げられる内容です。
例えば、私が以前見たものでは次のような記事があります。
おっしゃることには同意します。
ですが、現在の事態は、荒らし行為をしたユーザーの態度に対する指摘だと見ています。投稿の質がどうこうというのは、論点から外れているように思います。
非友好的な反応は、書き手に荒らし行為の前歴があるという背景のためでしょう。内容がどうこうというのは不要な蛇足だと思います。
だからこそ、その点が疑問なのです。
むしろ、みんなが「この人はアビューザーです!」という反応だったなら、こんなコメントは付けなかったでしょう。ところが、コメントの大半は元の文章の質を論じるものだったので、その点がおかしいということです。本当にアビューズが問題だからそうなったのだとしたら、文章の質がどうこうと言うのは完全に不要な蛇足ではないでしょうか。
同意します。
しかも「2025年5月から私一人で軍隊で作り始めました!」というのを見ると、企業ブログでもないですし……
もちろん、共有された内容が「当然やるべき作業」であることは否定しがたいですし、
「差別化の話もなく、本人の習作レベルの内容」であるのもその通りですが、
GeekNewsはこういうものを共有してはいけない雰囲気の場だったのでしょうか?
当然やるべき作業をやってみた経験を共有してはいけないのでしょうか?
差別化のない経験は共有してはいけないのでしょうか?
習作レベルの経験は共有してはいけないのでしょうか?
そう見えたのかもしれませんね。私が下記のようなコメントを付けた理由は2つありました。1つ目は、最初に上がった show gn の投稿がアビューズ行為として flagged されていたことです。1日後にご本人が自身の velog 記事を要約して新しく投稿されましたが、その記事自体が実質的にここに上がるに値する内容なのか、執筆者本人の悩みや努力が見えていたのかと問われれば、ほかの方々の意見と同じく、検索は一般的にある程度技術が出そろっている領域であり、技術的な部分よりもブログの内容自体が遠回しにご本人のサービスの宣伝の延長線上にあるように思えたため、そのようなコメントを残しました。
abuse フラグで悪い印象を持たれていることが、いちばん大きいのでしょうね。
ブログの内容自体が自社サービスの宣伝の延長線上にあるのは、ほかの企業の技術ブログも同じですから、それだけを理由に排斥するのはかなりセンシティブな基準だと思います。
そして、この文章で筆者自身の悩みや努力が見えたかという点についても、インデックスを張れば性能が改善するだろうという仮説が否定されたあと、実行計画も確認し、ビジネスロジックも考慮しながらクエリやスキーマを変えていく形で改善を繰り返し、目標性能を達成したのは、十分に悩み抜いた結果であり努力でもあるのではないかと思います。
ブログにも行って原文も読んできました。タイトルと実際の内容の間に少し乖離があるように感じますね。実装された機能や改善の方向性などは、すでに既存のさまざまなオープンソースで実装・反映されている部分ですし、今回作業されたのはご自身のサービスで当初シンプルに実装していた検索機能を高度化した部分ですが、タイトルだけを見るとアルゴリズムを大幅に改善したかのような印象を受けます。前回の記事も宣伝として flag されていたようですし、投稿される際にはもう少し検討が必要なのではないかと思います。
そのように感じられたのであれば申し訳ありません。タイトルを見て期待する内容は人それぞれ異なると思います。ただ、できるだけ期待する内容が近く、明確に伝わるタイトルを書くべきなのはその通りです。今後は注意いたします。
また、以前の投稿とは切り離して見ていただければと思います。以前の投稿では、私が未使用アカウント2つを使ってupvoteを試みたためflaggedされました。これは明らかに私のミスであり、記事自体に問題があったわけではないことをお伝えしたいです.
lower()インデックスの代わりに GIN インデックスを使ってみることは検討されたのか、気になります。どうせjdbctemplateで raw SQL を書かれているので、この機会に FTS はいかがでしょうか。CompletableFuture.supplyAsync()を使った非同期方式も、別途ExecutorServiceを指定しなければforkjoinpoolのcommonpoolを使うので、リクエストスレッドの代わりに使う
commonpoolがいっぱいになる程度まで(CPU コア数 - 1)同時接続者が増えると、さばききれなくなる可能性があります。この部分は reactive 方式に変更するか、JVM のバージョンを上げて仮想スレッドを導入するほうが、すっきり解決できると思います。
こんにちは! まず、フィードバックのコメントを付けてくださって本当にありがとうございます。
GINインデックスは、このケースでは必要ないと判断しました。現在の検索語オートコンプリート推薦APIでは、
term自体だけが必要です。そのtermがどの記事に属しているかは必要ありません。一方で、検索APIではGINインデックスに似たインデックスを使用しています。Postgresの拡張機能である paradeDB を活用して、BM25インデックスを使用しています。
投稿では詳しく触れていませんが、現在は
ExecutorServiceを別途指定して使用しています。ただし、おっしゃるとおり、reactive方式や仮想スレッドも今後検討してみます。今回の文章と前回の文章に関して、まずお詫び申し上げます。
使っていないアカウント2つで upvote してしまったのは、私のミスであり、愚かな行為でした。
長い時間をかけて取り組んだプロジェクトを、もっと多くの人の目に留めてもらいたいという思いから、誤った行動を取ってしまいました。
しかし、たとえそうした理由があったとしても、ルール違反を正当化できないのは事実です。
私が軽率に入れた upvote のせいで、誰かの投稿順位は下がっていたはずですし、サイトの秩序も乱してしまったと思います。
また、flagged された翌日に別の新しい投稿をしたことも、十分に誤解を招く行為だったと思います。
正直に言えば、サイトの利用制限が特になかったため、すぐに投稿してもよいのかと思ってしまいました。これは私の考えが浅かったです。
今になって考えると、制裁の有無に関係なく自重すべきでした。
逆の立場で考えてみれば、私自身でも、自分の好きな場所で誰かが同じ行動をしていたら、よくは思わなかったはずです。
私はこれまで、開発を始めてから無条件に「共有」は良いことだと考え、実践してきました。
ですが今回をきっかけに、共有すべき場所と、共有すべきタイミングはそれぞれあるのだと感じました。
また、誰かが愛着と関心を持っている場所に自分が新しく入ってきたのであれば、まず相手を最大限尊重するべきだと感じました。
だからこそ、利用規則から先に読み、サイトの雰囲気も見ながら、それに反する行動はしてはいけなかったと思います。
自分の過ちを認め、その説明としてこの場をお借りしました。
今後は、より成熟した姿勢で利用できるようにします。
:+1:
興味深く読みました。最初は単にインデックスを張ったという話なのかな?と思ったのですが、そこにとどまらずさまざまな方法を試して共有してくださっていて良いですね。今後はおっしゃる通り trie を使ってみるのも良いでしょうし、あるいは最近よく検索されているトレンド term にもう少し重みを与える、といった形で改善してみても良さそうですね!
一つ気になったのは、term と decomposed term の両方を OR 条件で検索されていましたが、decomposed term のほうが上位互換なのでこのフィールドだけを検索してもよいのでは、という点です。クエリが「neng」でも「n-e-o-ng」に分解されるので、「Naver」で検索できるのではないかと思ったためです。実際に term が「neng」であるものも同じように検索されるはずですし。
おっしゃる通り、decomposed termだけで検索しても十分です。これがある以上、termは不要な条件だったのですが、その点を考慮できていなかったようです。おかげで修正できました。ありがとうございます!
GeekNewsを見に来た人たちが見たい内容かというと、ちょっと微妙では? という感じがしなくもないですね。
何がそんなに大げさなのか、本当に理解できません。
レコード数が100万件、1000万件といった規模でもなく、10万件を少し超える程度の規模だということはタイトルの時点で明示されているのに、そこで基本に忠実であることより何か大げさな最適化を期待すること自体、少しおかしくないでしょうか? いったい何をそんなに大げさに期待していたのか気になります。
DBがきちんと最適化されていない状態で、基本に忠実に一つずつ整えていく構成の記事を投稿したことが、それ自体でそこまで釣り扱いされなければならないのか、よく分かりません。 私は、「最高の何かではないものをここに載せること自体が間違いだ」といった排他的な雰囲気は有害だと思います。
> そこで基本に忠実であることよりも、何か大げさな最適化を期待すること自体、少しおかしくありませんか?
人は知っている分だけ見えるものです。
理解しやすくするために、私は今、掲示板作りの例を考えています。
初心者開発者に最初のポートフォリオとしてよく勧められていたのが、掲示板作りです。
単純に考えれば簡単です。
投稿して、一覧に表示されれば終わりです。本当に簡単に作るなら、バックエンドのDBすら必要ないかもしれません。
しかし、人は知っている分だけ見えるものです。
掲示板を本気で作るなら、DBにはじまり、コメント機能、ログイン、さらにログインを発展させればOAuth認証やJWT、単純な投稿機能でも画像や動画の添付、書式のサポート、XSSをはじめとするセキュリティまであります。
同じテキストでも、読む人の背景知識によって思い描くイメージは大きく変わりえます。
kunggomさんがタイトルを見てどのような自動補完を想像されたのかは分かります。
ですが、読む読者はそれぞれ異なる人生を歩んできており、結局のところ読者が想像した機能は互いに大きく異なるはずです。
どのような意図でコメントを書かれているのかも分かります。
私もその意見には同意しますが、今この記事を書いた方の状況とはあまり合っていない話だということは、お分かりいただけると信じています.
「今この記事を書いた方の状況とはあまり合っていない話」という部分について、もう少し説明していただけますか?
原文によれば、当該プロジェクトは「個人プロジェクトであり、トラフィックが非常に多かったり、収益を上げなければならないサービスではない」と明記されています。したがって、何か大がかりな最適化が入るとすれば、それは単に個人的な好奇心などによるものであって、実用的な理由ではないだろうと推測できます。なので、その程度の技術的努力が投入されていないことを不自然だとは思わないのですが、なぜ一部の方々の反応だけが強く否定的なのか理解できないのです。タイトルで引用されている数値のような部分も、本文の内容と食い違っているわけではありませんし。
私は、kunggomさんが私の言った掲示板のたとえすら理解できないほど背景知識のない開発者だとは思っていません。
今の意見の違いは、Abusingユーザーに対する認識から来ているようなので、最後に申し上げます。
私が期待していたのはセマンティック検索です。
セマンティック検索というものは、AIブームの今においてまったく現実味のないテーマでもありませんし、個人でも十分に実装可能なものだということはご存じだと信じています。
そもそも私たちはタイトルをクリックする時点で、記事を書いた人の背景を理解したうえでクリックしているわけではありませんが、もしトラフィックが非常に多かったり収益を出さなければならないサービス ではないとしても、十分に実装可能だという話です。
そして私は今、タイトルについてだけ話しています。
> 原文によると、そのプロジェクトは〜
タイトルを見て想像していたイメージについて話しているので、この部分は今の私たちの会話では必要のない部分でしょう。
> 今この文章を書いた人の状況
今、kunggomさんが文章を書いた人をどう見ているのか分かった気がします。初心者開発者で、どんな文章を書いても理解してあげなければならない開発者だと見ているようですね。
昨日も言ったように、flaggedされていなければ私もそれに同意したでしょうが、書いた文章で推薦操作をした時点で、この話は無意味です。
> そして、もし本当にアビューズが摘発された人が翌日にまた文章を書くことが問題だと考えるなら
上ではこのようにおっしゃっていましたね。
flaggedされたあとも文章を書く自由があるなら、それについて批判する自由もあります。
ご本人がおっしゃったように、今このコメントでflaggedされた人に少し厳しめに言うことが問題だと思うなら、コメントで指摘するのではなく運営陣に提案してみてください。
埋め込みを入れるなどして、ぐちゃぐちゃに入力しても意図を汲んで検索候補を推薦してくれる、そういう種類のサービスについての最適化経験の共有を想定された、ということなのですね。
そういうものなら、むしろ「検索語推薦」くらいのタイトルから期待すべき内容なのではないかと思いますが、どのようなものを予想されていたのかは理解しました。
アビューズに批判的な立場は理解しますが、最後の一文は、論点を技術的未熟さからコミュニティ規則違反の問題へとさりげなくすり替えて、「あなたの論理と主張であなたを反論してあげよう」という拙い太極拳の試みのように見えて、少し残念です。
むしろ最初からアビューズ一点だけを批判していたなら、説得力があったはずです。本当にそうであったなら、たとえ実際にあの文章に、あなたが本来期待していたと主張する最新DBMSにおけるベクトル埋め込み最適化などの内容が含まれていたとしても、あるいは「控えめなタイトル」が使われていたとしても、書き手の最近のアビューズ履歴に対する敵対的な反応は出ていたでしょうし、その点について私は何の異論もありません。それは技術的内容とはあまり関係のない話ですから。
私が反対しているのは、その様相がなぜ「技術的未熟さ」への指摘として表出するのか、という点です。アビューズが容認できない行為なら、当然内容とは無関係に非難されてしかるべきでしょう。であれば、そこに内容への批判が入る理由があるのでしょうか。ところが、ここについたコメントはどれも内容が技術的に未熟だというニュアンスのものが多数です。crawlerさんも私に「初心者開発者の掲示板作り」のような比喩を使いながら、「知っているだけ見える」とおっしゃっていましたしね。こうなると、アビューズというのはむしろ副次的な、後から付け足された問題なのではないかと疑ってみるべきではありませんか。
コメントの内容どおりであれば、もし元の文章が本当にcrawlerさんの期待する種類の内容だったとしても、アビューズそのものだけで批判したはずです。あるいは、まさかアビューズをしていたにもかかわらず、ご自身としては文章の内容が気に入った場合には、「厳しく」語る自由を行使する必要はない、ということなのでしょうか。
ですので、改めて質問します。本当に元の書き手のアビューズのために書き手を批判しているのであれば、アビューズではなく内容に関する批判を中心にコメントを書かれた理由は何でしょうか?
「他の人の話す自由を妨げた」という部分について、根拠はありますか? これは少し理解できません。この場に対する管理権限が私にあって、他人が投稿やコメントを書くのを遮断できるわけでもないのですが。実際、こうして長いコメントも問題なく書かれているではありませんか。
単に他人の意見に反対するコメントを書くことが他人の話す自由を妨げることだというのなら、crawlerさんも今まさに私の発言の自由を侵害していると見なすべきでしょう。そうでないなら、論理的にはダブルスタンダードではありませんか?
そして、crawlerさんも認めたように、結局のところアビュージングかどうかは判断基準においてまったく重要ではなかった、ということです。
これは「昨日言ったように、flaggedされていなければ私もそこには同意しましたが、書いた投稿で推薦操作をした時点でこの話は無意味です。」という内容と矛盾しませんか?
今も引き続き論点と主張が変わっているように見えるので、どれか一つに固定していただければと思います。
私は、コミュニティの話題と十分に関連していてAIスロップでもない文章に対して、「この記事は私たちのコミュニティの水準にふさわしくない、質の低いものだ」と集団で非難する(あるいはそう見える)行為は、もしかすると投票操作以上にコミュニティの成長と維持に有害だと考えています。というのも、それはそのコミュニティの対外的なイメージを排他的に見せてしまう可能性があり、その結果として潜在的な新規ユーザーの流入を大きく妨げかねないからです。
もちろん、だからといって批判をするなという話ではありません。ただ、少なくともこうした雰囲気は少しおかしいと思います。共通していたのは、自分が期待していた内容ではなかったという点への失望ばかりで、建設的だと思える分析やフィードバックは少数だったからです。
そして、もし本当にアビューズが発覚した人が翌日にまた投稿することが問題だと考えるのであれば、この機会に運営に正式に関連規定の追加を提案してみてはいかがでしょうか。すでにある程度の制裁はあると認識していますが、それでは不十分だとお考えのようですので。
私はむしろ理解できません。集団で組織的に非難するために投稿したものだと見ていらっしゃるのでしょうか? あなたの主張こそ、むしろ各個人が表明できる意見をネガティブに受け取っているように思えるのですが? 今後は開発日誌程度の文章(
printfで星を描く改善のために目標を立てて改善し、for文を使いました!)のような投稿が上がってきても、同じように温かい気持ちで見てくださることを願います。「六龍の時代」や「ウェブ三国無双伝」のように、他サイトのギャラリーでもご自身の宣伝をよくされていたようですね。
自分の未完成な成果物をお試し用のように掲げ、その後そのプロジェクトを簡単に放棄する態度を見ていると、この投稿と何が違うのかと思いますが……なぜ他人には厳しい物差しを当てるのでしょうか。
DCインサイドは子どもたちの遊び場だから好き勝手してもよくて、GeekNewsはご自身が愛着を持っている場所だから、誰か他の人が汚すのは我慢できないということでしょうか。
別に論理的に話したいわけではなく、ただダブルスタンダードぶりが斬新で言っているだけなので、反論するあなたの言うことが正しいです。アビューズ頑張ってください。
検索オートコンプリートAPIを最適化したサービスのようなタイトルですが、内容はただのDB検索最適化ですね。
商用ならOracleの最適化で十分対応可能ですし、オートコンプリート自体も既存サービスが多いです。差別化の話もなく、本人の習作レベルの内容です。
少し見ていて不快です