OmniAICreator/Qiita-1.07M huggingface dataset:
AtCoder ABC399 振り返り(緑コーダーがPythonでABC問題)

## AtCoder ABC399 振り返り

前回のABC398は用事により未チャレンジだったので、今回は2回ぶりのRating参加です。

結果は3問解答でした。あまりレーティングは気にしていないとはいえ、そろそろ緑陥落が見えてきてしまいました。

2週間間隔が空いたこと、水曜日あたりひどい胃腸炎になってしまい、体調が戻っていないことが敗因です（言い訳）。398は受けなかったなら受けなかったで、復習しておけばよかったなあ...。

C問題で解法をすぐに思いつかず、時間がかかってしまった & 1ペナしてしまったのも良くなかった。D問題は解けそうなんですけど、頭が働かずだめでした。


## [A - Hamming Distance](https://atcoder.jp/contests/abc399/tasks/abc399_a)

全探索して、文字が異なるものをカウントしました。

``` python
N = int(input())
S = input()
T = input()

count = 0
for i in range(N):
    if S[i] == T[i]:
        continue
    else:
        # 異なる文字をカウント
        count += 1
print(count)
```


## [B - Ranking with Ties](https://atcoder.jp/contests/abc399/tasks/abc399_b)

解き方を悩んだんですが、入力数列を逆順でソートしまして...

```
[3 12 9 9]
↓
[12 9 9 3]
```

「その数値が最初に現れる位置」が順位になります。
上の例なら 12 → 1番、9 → 2番、3 → 4番

``` python
N = int(input())
P = list(map(int, input().split()))
sorted_p = sorted(P, reverse=True) # 逆順にソート

answers = []
for i in range(N):
    r = sorted_p.index(P[i]) # 逆順ソートの配列の中で、indexを求める
    print(r + 1)
```


## [C - Make it Forest](https://atcoder.jp/contests/abc399/tasks/abc399_c)

1ペナでした。最初は幅優先探索で解くのかなと思ってやってたんですが、それだは答えが出ません...(これで1ペナ)。

「よくわかんないなー」と思って、鉄則本を見ていたら「最小全域木問題」のところで、解き方を思い出しました。この問題は、すべての辺の重みが1の最小全域木問題ですね...。

というわけで、Union-Find を使用して解きました。

``` python

# UnionFindは https://qiita.com/sano192/items/027d672129ac4cb42aa2#e---graph-destruction より
class UnionFind:
    def __init__(self,n):
        self.n=n
        self.parent_size=[-1]*n
    def leader(self,a):
        if self.parent_size[a]<0: return a
        self.parent_size[a]=self.leader(self.parent_size[a])
        return self.parent_size[a]
    def merge(self,a,b):
        x,y=self.leader(a),self.leader(b)
        if x == y: return
        if abs(self.parent_size[x])<abs(self.parent_size[y]):x,y=y,x
        self.parent_size[x] += self.parent_size[y]
        self.parent_size[y]=x
    def same(self,a,b):
        return self.leader(a) == self.leader(b)
    def size(self,a):
        return abs(self.parent_size[self.leader(a)])
    def groups(self):
        result=[[] for _ in range(self.n)]
        for i in range(self.n):
            result[self.leader(i)].append(i)
        return [r for r in result if r != []]

# 読み込み
N, M = map(int, input().split())
paths = defaultdict(list)
uv = []
for i in range(M):
    u, v = map(int, input().split())
    paths[u].append(v)
    paths[v].append(u)
    uv.append((u, v))

unionfind = UnionFind(N + 1)

count = 0 # 使用した辺の数をカウント
for path in uv:
    u, v = path

    # 既に連結されている場合はスキップ
    if unionfind.same(u, v):
        continue
    
    # 未連結の場合は、その辺を使用し連結する
    unionfind.merge(u, v)
    count += 1

print(M - count) # すべての辺の数 - 使用した辺の数

```
Terraform の自動実行スクリプト（Bash スクリプト）

## めんどくさがり御用達のスクリプトです


```
#!/bin/bash

# 色の定義
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# エラーハンドリング
set -e

# 並列処理の制限
PARALLELISM=100  

# 削除モードの確認
if [[ "$1" == "destroy" ]]; then
    DESTROY_MODE=true
else
    DESTROY_MODE=false
fi

# スクリプトの実行開始
echo -e "${BLUE} Terraform 自動実行スクリプト開始${NC}"

# Terraform Format
echo -e "${YELLOW} Terraform Format...${NC}"
terraform fmt -recursive
echo -e "${GREEN} Terraform Format 完了${NC}"

# Terraform Validate
echo -e "${YELLOW} Terraform Validate...${NC}"
terraform validate
echo -e "${GREEN} Terraform Validate 成功${NC}"

# Terraform Plan / Destroy Plan (tfplan を常に使用)
if [[ "$DESTROY_MODE" == "true" ]]; then
    echo -e "${YELLOW}  Terraform Destroy Plan...${NC}"
    terraform plan -destroy -out=tfplan -parallelism=$PARALLELISM -input=false
    echo -e "${GREEN} Terraform Destroy Plan 成功${NC}"
else
    echo -e "${YELLOW} Terraform Plan...${NC}"
    terraform plan -out=tfplan -parallelism=$PARALLELISM -input=false
    echo -e "${GREEN} Terraform Plan 成功${NC}"
fi

# Terraform Apply / Destroy (tfplan を適用)
if [[ "$DESTROY_MODE" == "true" ]]; then
    echo -e "${YELLOW}  Terraform Destroy 実行中 (tfplan 使用)...${NC}"
    terraform apply -auto-approve -parallelism=$PARALLELISM tfplan
    echo -e "${GREEN} Terraform Destroy 完了${NC}"
else
    echo -e "${YELLOW} Terraform Apply 実行中 (tfplan 使用)...${NC}"
    terraform apply -auto-approve -parallelism=$PARALLELISM tfplan
    echo -e "${GREEN} Terraform Apply 完了${NC}"
fi

# スクリプトの完了メッセージ
echo -e "${BLUE} Terraform の自動実行が完了しました！${NC}"

```
Supabase UI Library 開発効率を爆上げするコンポーネント集

# Supabase UI Libraryで開発効率を向上

Supabaseは、認証、ファイルストレージ、リアルタイムサブスクリプションなど、強力なアプリケーションを簡単に構築するための機能を提供します。しかし、これらの機能を最大限に活用するには、カスタムUIの構築が必要となり、開発に時間と手間がかかるという課題がありました。

そこで、開発者がより効率的にSupabaseを活用できるよう、便利で実戦でテスト済みのコンポーネントセット **「Supabase UI Library」** が開発されました。

## Supabase UI Libraryの主な特徴

このライブラリには、以下の便利なコンポーネントが含まれています。

* **認証関連**: サインアップ / サインイン、メール確認、パスワードリセット
* **リアルタイムサブスクリプション**: 共同作業アプリ向けのカーソル位置共有コンポーネント
* **ファイルストレージ**: 複数ファイルのアップロードを可能にするDropZoneコンポーネント
* **AIコードエディタ**: AIエージェントを正しい方向に導くためのルールセット

## Supabase UI Libraryで開発がもっと簡単に

Supabase UI Libraryを活用することで、Supabaseの強力な機能を最大限に活用したアプリケーション開発が、これまでになく容易になります。開発者は、UI構築にかかる時間と手間を大幅に削減し、より重要な機能の開発に集中できます。


## 参考

* Supabase UI ライブラリの発表 - YouTube
    * [https://www.youtube.com/watch?v=2TIuUjkCDFE](https://www.youtube.com/watch?v=2TIuUjkCDFE)
microCMSで記事を最新の10件だけ取得する方法




microCMSの管理画面ではこちらで取得したい値を設定し取得ボタンをクリックし
意図した値が返ってきているか確認する。

![スクリーンショット 2025-03-31 22.34.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704697/c731b89e-613f-4d19-82db-c51ff285180e.png)


```

取得結果が必要とする最新のデータが１０件表示されていればOK

{
    "contents": [
        {
            "id": "aaaaaa",
            "title": "記事１"
        },
        {
            "id": "bbbbb",
            "title": "記事2"
        },
        {
            "id": "cccc",
            "title": "記事3"
        },
        {
            "id": "dddd",
            "title": "記事4"
        },
        {
            "id": "eeeee",
            "title": "記事5"
        },
        {
            "id": "fffff",
            "title": "記事6"
        },
        {
            "id": "gggggg",
            "title": "記事7"
        },
        {
            "id": "hhhh",
            "title": "記事8"
        },
        {
            "id": "iiiii",
            "title": "記事9"
        },
        {
            "id": "jjjjj",
            "title": "記事10"
        },

    ],
    "totalCount": 17,
    "offset": 0,
    "limit": 10
}

```


意図した値が返ってきていたらOK！

任意のファイルにコードを記述する



```libs/microcms.ts
// 最新の記事一覧を取得
export async function getLatestPost() {
  const latestPosts = await client.get({
    endpoint: "blog",
    queries: { limit: 10, orders: "-createdAt", fields: "title,id" },
  });

  return latestPosts; 
}

```

タイトル一覧を表示させ、id をslugで運用しているのでこのようなコンポーネントにしました。


```components/LatestPostList.tsx
import Link from "next/link";
import React from "react";

interface PostList {
  postTitle: string;
  postSlug: string;
}

export default function PostList({ postTitle, postSlug }: PostList) {
  return (
    <>
      <Link
        href={`/blog/${postSlug}`}
        className="block pt-3 indent-2 text-sm hover:text-gray-400"
      >
        {postTitle}
      </Link>
    </>
  );
}
```

これで最新の１０件のタイトルとそれに紐付く記事のリンクが作成され
遷移できます。

```src/app/page.tsx
// 最新の記事の１０件を表示
{latestPosts.contents.map(
(latestPost: { id: string; title: string }) => (
  <PostList
    key={latestPost.id}
    postTitle={latestPost.title}
    postSlug={latestPost.id}
  />
)
)}
```

方法は色々模索中なのでよりベターな方法があれば
教えていただけるとうれしいです！！
社内チャットボットを作るにあたって考えたこと　～⑤フロー・プロンプト・その他～

# はじめに
2024年8月頃からAWS上でBedrockを使って社内向け生成AIチャットボットを作っています。
初めて生成AIを使ってみたところで色々考える点があったので、メモとして残しておくことにしました。

生成AI技術が日々すごいスピードで進歩しているので既に古い技術になっていそうなのと、そもそも初心者が書いておりますで、あまり技術的な参考にはならないと思いますが、ポエム的な感じ？でお読みいただけたら幸いです。

# 考えたこと⑤　フロー・プロンプト・その他

前回までは構成について書いてきました。
今回は最終回として、Difyのフローやプロンプト周りで考えたことをつらつらと書いていきたいと思います。

## フロー
### LLM操作はDify側で行う
開発初期の頃ですが、ナレッジベース＆回答生成を行うために、RetrieveAndGenerate APIを呼び出していました。初期の頃の質問したらちゃんとそれっぽい回答返ってくるね。くらいの時は問題なかったのですが、回答の形式だったり回答文言の正確性を求めるようになってきた段階になってくると段々と扱い辛くなってきました。
特に以下の2点がストレスでした。

- プロンプトがなかなか決まらず何度も何度も更新する時にAPI側で修正するのが面倒
- 回答として返却されるとデバッグしにくいし後続タスクでの使い勝手が悪い

このため、APIはRetrieve APIで検索だけ行うことにして、回答はDify側のLLMブロックで行うことにしました。DifyのLLMブロックでプロンプトを書くようになってからはかなり作業効率が良くなりました。

### LLMとコードの使い分け
LLMは本当に便利で何でもやってくれて、コードが書けない私には非常に有難く、JSONデータのパースなどの文字列処理もLLMに頼っていました。
しかし、LLMに頼りすぎると、便利の反面、以下のような問題がありました。
- なかなかビタっと言うこと聞いてくれるような指示を出すのが難しい
- 気分によっていろんな動きをされるのでイレギュラーなデータになることがしばしば
- LLMに頼るとちょっと時間かかる

そんなに難しい処理ではないのに指示だしに時間取られたくないということで結局コード化しました。
文字列操作や判断など正確さを求めるような処理はLLMではなくコード化するのが良いと思います。逆にLLMにはコードを書くときに助けてもらう感じで。

## プロンプト
### 指示は小さいものにする
LLMへの指示においては、気が付いたら色んなことを書いていたことにありました。
例えば、①RAG結果から適切な部分を抽出して、②ここの箇所に回答書いて、③回答なかったらこう書いて、④但しほにゃの場合は…etcみたいな感じです。
ここの指示を増やせば増やすほど正確性を出すのが難しくなっていった感じがありました。
①は必要だと思いますが、②はXMLタグに挟むくらいで良いでしょうし、③以降はコードで処理したほうがいいかもしれません。
色んな制約を与えたり段落で書いたりなど色んなテクニックがあるかと思いますが、コード処理しやすい形式として出すくらいのシンプルな指示がいいのではないかと思いました。

### 指示の言葉は正しく使う
ここは個人的に非常に苦手な部分なのですが、言葉のチョイスを間違えると動きが変わってきます。
例えば今回あったのは「回答して」「出力して」の違いでした。
過去のQAの文面を正確に出したいのにLLMが自分の意見を入れてくるといったケースが多く、見直したら「回答して」の指示が入っていたためでした。チャットボットへの指示なので何の違和感もなく「回答して」と指示していたのですが、「出力して」が正解でした。
見直すと当たり前のことなのですが、このあたりの指示の言葉の使い方は大事だなと思いました。

## その他
### スコアの取得
チャットボットの機能として、LLM回答の信頼性スコアが欲しかったのですが、これはApplyGuardRail APIで取得することにしました。このスコアの数字自体もどの程度信頼できるものなのか…と思うこともありますが、ユーザや運用者がLLM回答の評価に使えるいいスコアだと思いました。

https://dev.classmethod.jp/articles/guardrails-for-amazon-bedrock-contextual-grounding-check/

### プロンプトテクニック使いこなせず…
AdvancedRAGやHyDE、RAGフュージョンなどのテクニックを試してみたのですが、使い方が悪いのか、今回のチャットボットような簡単なものに合わないのか、精度向上に繋がらず私には使いこなせませんでした。。いずれにせよ勉強不足だと思うので次の機会にまた試してみたいと思います。


# 考えた結果
今回はプロンプトやフローを組み立てる上での考えたことを記載させていただきました。
初歩的なことばかりだと思いますが、LLMを使うにあたって色んな気づきがありました。
書いているうちにも入ってきている新しい技術をどんどん取り入れていって、使い易いチャットボットを作っていきたいと思います。
今回で最終回になります。全体的に拙い文章であったかと思いますが、最後までお読みいただきありがとうございました。
スケーリングとは

# スケーリングとは
システムの利用者の数に応じて、`システムの規模を拡大・縮小する`こと。

# スケーラビリティとは
スケーラビリティとは`スケーリングのしやすさ`のこと。

# スケーリングの種類

## 水平スケーリング
システムの利用者の数に応じて、`コンテナの数を増加・減少させる`ことによりシステムの規模を拡大・縮小するやり方。

コンテナを増やすことを`スケールアウト`という。
コンテナを減らすことを`スケールイン`という。

## 水平スケーリングのメリット
簡単な処理を大量に処理するときはおすすめ。

## 水平スケーリングのデメリット
複雑な処理をすることは難しい。

## 水平スケーリングの種類

#### ステップスケーリングポリシーとは
CPUやメモリ使用率に応じて定義されたコンテナ数に合わせるやり方。

#### ターゲット追跡スケーリングポリシーとは(一番メジャー)
CPUやメモリのターゲット使用率になるようにコンテナ数を増減させるやり方。

## 垂直スケーリング
システムの利用者の数に応じて、`コンテナの性能を向上・低下する`ことによりシステムの規模を拡大・縮小するやり方。

コンテナの性能を向上させることを`スケールアップ`という。
コンテナの性能を低下させることを`スケールダウン`という。

## 垂直スケーリングのメリット
複雑な処理をするときにおすすめ

## 垂直スケーリングのデメリット
簡単な処理を大量に処理することは苦手。
Java:強化されたswitch 文

## 強化された Java の switch 文（Java 14以降）
Java 14以降、switch文は 表現力・可読性・安全性が大幅に向上しました。

### 従来のswitch文の課題
breakを忘れるとフォールスルー（次のcaseに処理が進む）

switchは「文（Statement）」であり、値を返せない

複数のcaseに共通処理を書くと冗長になる
```　
例（従来）:
switch (day) {
    case "MON":
    case "TUE":
        System.out.println("Weekday");
        break;
    case "SAT":
    case "SUN":
        System.out.println("Weekend");
        break;
}
```
### 強化されたswitch文の特徴
1. switch式（Expression）
switchが式として使える（値を返せる）

-> を使ってシンプルに記述可能

```
String result = switch (day) {
    case "MON", "TUE", "WED", "THU", "FRI" -> "Weekday";
    case "SAT", "SUN" -> "Weekend";
    default -> "Unknown";
};
```
または yield を使ってブロック形式もOK：

```
int dayOfWeek = switch (day) {
    case "Sunday" -> 0;
    case "Monday" -> 1;
    default -> {
        System.out.println("Unknown day");
        yield -1;
    }
};
```
2. 複数のcaseをカンマでまとめられる
```
case "SAT", "SUN" -> "Weekend";
```
→ 複数の条件を1行でまとめて書ける！

3. パターンマッチング（Java 17～）
型判定や条件分岐もcaseで直接書ける

```
switch (obj) {
    case String s when s.length() > 5 -> System.out.println("長い文字列");
    case Integer i -> System.out.println("整数: " + i);
    default -> System.out.println("その他");
}
```
4. その他の改良点
Enum型・Sealedクラスへの対応強化

nullやdefaultの柔軟な扱い

網羅性チェックの導入（抜け漏れを防止）
【Laravel】キューを使ったメール送信処理の設計メモ：ジョブと遅延実行（Delay）の活用

こんにちは！Webエンジニアとして働き始めてそろそろ１年目になります。

最近、参画している案件で、特定の時間に**メール・通知を送信する方法**　について調べる機会がありました。
今回は、その経験で得た知見や「こうすれば良かったかも」という点を、自分自身の**備忘録**として、そして同じようにLaravelを学んでいる方々の参考になればと思い、まとめてみることにしました。

基本的なキューやワーカーの話も少し含みますが、今回は**メールや通知の遅延実行**に焦点を当てて書いていきます。

## なぜメール送信にキューを使うのか？（おさらいと深掘り）

まず、なぜメール送信のような処理にキューを使うのが良いのか、簡単におさらいさせてください。

- メール送信処理（特に外部のSMTPサーバーとの通信）は時間がかかることがあります。これをユーザーのリクエスト中に同期的に行うと、ユーザーを待たせてしまいます。キューを使えば、送信処理をバックグラウンドに回せるので、ユーザーはすぐにレスポンスを受け取れます
- 短時間に大量のメール送信リクエストが発生した場合でも、キューが緩衝材となり、一度にサーバーへ高い負荷がかかるのを防げます。また、並列で処理を行うためより高速に処理を行うことが可能です。
- ネットワークの問題やメールサーバーの一時的な不調で送信に失敗しても、キューなら自動で再試行（リトライ）してくれます。これにより、メールの送信漏れリスクを減らせます

## 特定の時間にメールを送りたい！ 遅延実行 (Delay) の使い方
毎日決まった時間にメールや通知を送信したいという要件がありました。
この時に実現できるパターンとしては下記の２種類が考えられるかと思います。
1. Cronを用いたバッチ処理で行う
2. キューワーカーにて遅延実行をすることで実現する
今回は、２つ目の方法に焦点を当てて行きたいと思いますl。
※おそらく本来の使い方ではない気がするので、その時間にバッチ処理を行うと負荷が気になるなどの事情がなければバッチ処理にて行う方がいいのではないか？とも思います。詳しい方がいらっしゃいましたら、是非コメントで教えてください！

### ジョブをディスパッチする際に delay() メソッドを使います。
```
use Carbon\Carbon; // 日時操作に便利なCarbonライブラリ

// --- 例1: 10分後にジョブを実行 ---
SendSpecificEmail::dispatch($user, $data)
                 ->delay(now()->addMinutes(10));

// --- 例2: ユーザー登録から3日後に実行 ---
$registrationDate = $user->created_at; // ユーザー登録日時
SendSpecificEmail::dispatch($user, $data)
                 ->delay($registrationDate->addDays(3));

// --- 例3: 特定の日時（2025年4月15日 午前9時）に実行 ---
SendSpecificEmail::dispatch($user, $data)
                 ->delay(Carbon::parse('2025-04-15 09:00:00'));

// もちろんキュー指定と組み合わせることも可能
SendSpecificEmail::dispatch($user, $data)
                 ->onQueue('scheduled_emails') // 別のキューにするなど
                 ->delay(now()->addHours(1)); // 1時間後
```
delay() に DateTimeInterface インスタンス（Carbon インスタンスや now() ヘルパの結果）を渡すことで、指定した日時までジョブの実行を遅らせることができます。

:::note info
delay() を使うと、database ドライバの場合、jobs テーブルの available_at カラムに未来の日時が設定されます。キューワーカーは、この available_at が現在時刻を過ぎているジョブだけを取得して実行する仕組みになっています。
:::

:::note warn 注意点

ワーカーが動いている必要: 当然ですが、指定した日時になってもキューワーカーが起動していなければジョブは実行されません。Supervisorなどでワーカーが常に稼働していることが前提です。
正確な時間ではない可能性: delay() は「少なくとも指定した時間までは実行しない」という意味合いです。ワーカーが他のジョブを処理中だったり、起動タイミングによっては、指定時刻ぴったりではなく、少し遅れて実行される可能性があります。ミリ秒単位の厳密な実行時間制御には向きません。
:::

## それぞれのメリット・デメリット
メール送信処理を行うジョブクラスを作成し、そのジョブをキューに追加する際に delay() メソッドを使って送信時間を指定する場

#### メリット:

実装が容易: 単純なメール送信であれば、比較的簡単に実装できます。
柔軟な送信時間設定: 個々のメールに対して異なる送信時間を設定できます。
少量のメールに適している: 数件程度のメールを個別に異なる時間に送信したい場合に便利です。
#### デメリット:
大量のメールには不向き: 大量のメールを異なる時間に送信する場合、キューに大量のジョブが登録され、管理が煩雑になる可能性があります。
リソース消費: 個々のメール送信が独立したジョブとしてキューに追加されるため、システムリソースを個別に消費します。
送信時間のずれ: キューワーカーの処理状況によっては、指定した時間から若干の遅延が発生する可能性があります。
スケジューリングの複雑化: 多数のメールに対してそれぞれ異なる送信時間を設定する場合、スケジューリングの管理が難しくなります。

### まとめ
今回はキューワーカーを用いて遅延処理をする方法について紹介してみました。
バッチ処理で実装するだけでなく、Delayの方法でも実装を行うことができるため、メリット・デメリットを考慮した上で実装してみてください
atcoder_水色精進記録17_ABC335e

# Atcoder水色精進記録
ABC335
E - Non-DecreasingColorfulPath
https://atcoder.jp/contests/abc335/tasks/abc335_e

# アルゴリズム・データ構造
ダイクストラ

# 考察
Sが広義短調増加である必要があるため
u,vが与えられた時に、
A[u]<=A[v]の時は、u->vのpathを追加
A[v]<=A[u]の時は、v->uのpathを追加
上記は排他ではなく、並列で確認
とすれば、無効な辺は考えなくて良くなる。

BFS,DFSで全てのpathを全探索すると計算量がオーバー

現在いる頂点より低い頂点に訪れることはできない
頂点が低い順にpathを確定すれば良さそう
→頂点の重さをkeyとしてダイクストラ的な順番で計算すれば求められる

# 提出
https://atcoder.jp/contests/abc335/submissions/64400192

# 感想
ダイクストラが久々だったが、実装を空で書くことができた。
【現役シリコンバレーエンジニアが教えるPython 3 入門 + 応用】Section7での不明点_1

## 概要

Udemyで酒井潤さんの講座を学習させてもらった際によくわからない部分があったので残したいと思います。

[現役シリコンバレーエンジニアが教えるPython 3 入門 + 応用 +アメリカのシリコンバレー流コードスタイル](https://www.udemy.com/course/python-beginner/?srsltid=AfmBOoop1KFzaPJbuc8XjXQBWzWaG-7MIlW3VbbMcOs5Tobg6M6vkciZ)

以下のようなコードがあります

```python
class Person(object):
    def __init__(self, age = 1):
        self.age = age

    def  drive(self):
        if self.age >= 18:
            print('OK')
        else:
            raise Exception('No')

class Baby(Person):
    def __init__(self, age=1):
        if age < 18:
            super().__init__(age)
        else:
            raise ValueError

class Adult(Person):
    def __init__(self, age=18):
        if age >= 18:
            super().__init__(age)
        else:
            raise ValueError
baby = Baby()
adult = Adult()

class Car(object):
    def __init__(self, model=None):
        self.model = model
    def run(self):
        print('run')
    def ride(self, person):
        person.drive()

car = Car()
car.ride(adult)
```

ここでCarクラスから作成されたcarオブジェクトでrideメソッドを、adultを引数として渡して呼び出しますよね。
実行すると以下の結果になると思います。

```python
OK
プロセスは終了コード 0 で終了しました
```

ここで何故エラーにならずOKが正しく出力されるか直感的によくわかりませんでした。

それで調べてみるとすごく単純なことでした。

**rideメソッドの()内に記載されているpersonって渡された引数を受け取る文字列のような役割だったということです。**
Personクラスがあるのでそちらと関連付けてごっちゃになってしまいましたけど、要するにpersonの部分がalienでもmonsterでも成立するわけですね。

**つまりcarオブジェクトでrideメソッドを実行する際は引数としてadultを渡していましたが、これがCarクラスのrideメソッドのpersonに格納されるわけということです。**

実質的には adult.drive が実行されているような感じでそれなら結果としてOKが出力されるのも納得いきました。
MIDIファイルとPythonコード


## Pythonを使ってMIDIファイルを作成し、WAVフォーマットに変換する方法

この記事では、MIDIファイルを作成し、それをFluidSynthを使ってWAVフォーマットに変換し、Pythonで再生する方法を紹介します。このプロセスには、`mido`、`fluidsynth`、`pyfluidsynth`などのライブラリを使用します。

### ステップ1: 必要なパッケージのインストール

まず最初に、必要なPythonパッケージと外部ツールをインストールします。

```bash
!pip install mido
!apt install -y fluidsynth
!pip install pyfluidsynth
```

以下は各ライブラリの簡単な説明です：
- `mido`: MIDIファイルを操作するためのPythonライブラリです。
- `fluidsynth`: ソフトウェアシンセサイザーで、MIDIをWAVファイルに変換するのに使用します。

### ステップ2: SoundFontのダウンロード

FluidSynthを使用するためには、SoundFontという音色データが必要です。最初にSoundFontをダウンロードします。

```bash
!wget -q https://github.com/urish/csr8670/raw/master/tools/soundfonts/FluidR3_GM.sf2 -O soundfont.sf2
```

### ステップ3: MIDIファイルの作成

次に、簡単なメロディを作成し、それをMIDIファイルとして保存します。例えば、「Twinkle Twinkle Little Star」のメロディを使用します。

```python
from mido import MidiFile, MidiTrack, Message

# MIDIファイルを作成する関数
def create_midi(notes, midi_filename):
    """
    MIDIファイルを作成し、保存する関数。
    
    Parameters:
    notes (list): MIDIノート番号のリスト。
    midi_filename (str): 保存するMIDIファイルの名前。
    """
    midi = MidiFile()
    track = MidiTrack()
    midi.tracks.append(track)

    note_length = 480  # 四分音符の長さ
    velocity = 64      # ノートのベロシティ（音量）

    # ノートオンとノートオフメッセージを追加
    for note in notes:
        track.append(Message('note_on', note=note, velocity=velocity, time=0))
        track.append(Message('note_off', note=note, velocity=velocity, time=note_length))

    midi.save(midi_filename)

# 「Twinkle Twinkle Little Star」のノートリスト
twinkle_notes = [60, 60, 67, 67, 69, 69, 67, 65, 65, 64, 64, 62, 62, 60]

# MIDIファイルを作成
twinkle_midi = "twinkle.mid"
create_midi(twinkle_notes, twinkle_midi)
```

### ステップ4: MIDIファイルをWAVフォーマットに変換

次に、作成したMIDIファイルをWAVフォーマットに変換します。これにはFluidSynthを使用します。

```python
import subprocess

# MIDIをWAVに変換する関数
def convert_midi_to_wav(midi_file, wav_file, soundfont="soundfont.sf2"):
    """
    MIDIファイルをWAVファイルに変換する関数。
    
    Parameters:
    midi_file (str): 入力のMIDIファイルのパス。
    wav_file (str): 出力するWAVファイルのパス。
    soundfont (str): 使用するSoundFontのパス。
    """
    subprocess.run(["fluidsynth", "-ni", soundfont, midi_file, "-F", wav_file, "-r", "44100"])

# 「Twinkle Twinkle Little Star」のMIDIをWAVに変換
twinkle_wav = "twinkle.wav"
convert_midi_to_wav(twinkle_midi, twinkle_wav)
```

### ステップ5: WAVファイルを再生

作成したWAVファイルを再生するために、IPythonの`Audio`クラスを使用します。

```python
from IPython.display import Audio

# 「Twinkle Twinkle Little Star」のWAVファイルを再生
Audio(twinkle_wav)
```

### 結果

これで、「Twinkle Twinkle Little Star」のMIDIファイルを作成し、それをWAVフォーマットに変換して再生することができました。
【Android】Fragmentに引数はNGと学んだ話

## 起きたこと
画面見にくいなーと思ってAndroid端末の設定から表示サイズ変更したところアプリが落ちた。
```
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.simplefragment/com.example.simplefragment.MainActivity}: androidx.fragment.app.Fragment$InstantiationException: Unable to instantiate fragment com.example.simplefragment.BlankFragment1: could not find Fragment constructor
```

`InstantiationException`なるものが出力されたので調べてみた。

## 原因
調べたら記事がわんさか出てきた。どうやら引数付きのFragmentが原因らしい。
Fragmentは引数なしのデフォルトコンストラクタを持っており、Fragment生成時はこのデフォルトコンストラクタが必要のため呼び出される。
しかし、引数ありのカスタムコンストラクタは許容されておらず`InstantiationException`が出力されてしまうとのこと。

```Kotlin
class BlankFragment1(
    testParam: String ・・・これがいけない
) : Fragment() {
```

参考：
https://developer.android.com/reference/android/app/Fragment

## 学び
結局エラーで落ちないようFragmentの引数を削除する方向で修正。
今後はFragmentにはパラメータを渡さないことを心がけたい。。。
C#でIoTプログラミング on ESP32 #10 - SHT40

I2C接続のデジタル温湿度センサーのサンプルを紹介します。

## ハードウェア
・Freenove ESP32-S3-WROOM Board or Espressif ESP32-S3-DevKitC
・Adafruit SHT40

## 配線
![SHT40.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/fc21a76d-8eb2-42d8-9f2a-6f93e3adfd19.png)

## 導入パッケージ
・nanoFramework.Hardware.Esp32
・nanoFramework.System.Device.I2c

## プログラミング
```C#:Program.cs
using nanoFramework.Hardware.Esp32;
using System;
using System.Device.I2c;
using System.Threading;

namespace ESP32S3_SHT40
{
    public class Program
    {
        public static void Main()
        {
            Configuration.SetPinFunction(8, DeviceFunction.I2C1_DATA);
            Configuration.SetPinFunction(9, DeviceFunction.I2C1_CLOCK);

            var device = I2cDevice.Create(new I2cConnectionSettings(
                1,
                0x44,
                I2cBusSpeed.FastMode));

            while (true)
            {
                device.WriteByte(0xfd);
                Thread.Sleep(10);

                byte[] data = new byte[6];

                device.Read(data);

                ushort rawTemp = (ushort)(data[0] << 8 | data[1]);
                double temp = -45 + 175 * (rawTemp / 65535.0);

                ushort rawHum = (ushort)(data[3] << 8 | data[4]);
                double hum = -6 + 125 * (rawHum / 65535.0);

                Console.WriteLine($"Temp: {temp:F2}℃, Hum: {hum:F2}%");

                Thread.Sleep(1000);
            }
        }
    }
}
```
【コマンド】Docker

## 目次
- [基本](#基本)
    - [バージョンを表示する](#バージョンを表示する)
    - [システム情報を表示する](#システム情報を表示する)
    - [サブコマンド一覧を表示する](#サブコマンド一覧を表示する)
- [イメージ管理](#イメージ管理)
    - [イメージ一覧を表示する](#イメージ一覧を表示する)
    - [イメージをダウンロードする](#イメージをダウンロードする)
    - [イメージを削除する](#イメージを削除する)
    - [Dockerfileからイメージをビルドする](#dockerfileからイメージをビルドする)
- [コンテナ管理](#コンテナ管理)
    - [起動中のコンテナ一覧を表示する](#起動中のコンテナ一覧を表示する)
    - [コンテナ一覧を表示する](#コンテナ一覧を表示する)
    - [コンテナの詳細情報を表示する](#コンテナの詳細情報を表示する)
    - [コンテナを作成する](#コンテナを作成する)
    - [コンテナを削除する](#コンテナを削除する)
- [コンテナ操作](#コンテナ操作)
    - [コンテナを起動する](#コンテナを起動する)
    - [コンテナを停止する](#コンテナを停止する)
    - [コンテナを強制停止する](#コンテナを強制停止する)
    - [コンテナを再起動する](#コンテナを再起動する)
- [コンテナ接続](#コンテナ接続)
    - [コンテナに接続する](#コンテナに接続する)
    - [コンテナを停止しないで切断する](#コンテナを停止しないで切断する)
    - [コンテナから切断して停止する](#コンテナから切断して停止する)
- [ネットワーク管理](#ネットワーク管理)
    - [ネットワーク一覧を表示する](#ネットワーク一覧を表示する)
    - [ネットワークの詳細情報を表示する](#ネットワークの詳細情報を表示する)
    - [ネットワークを作成する](#ネットワークを作成する)
    - [ネットワークを削除する](#ネットワークを削除する)
- [ネットワーク接続](#ネットワーク接続)
    - [コンテナをネットワークに接続する](#コンテナをネットワークに接続する)
    - [コンテナをネットワークから切断する](#コンテナをネットワークから切断する)
- [ボリューム管理](#ボリューム管理)
    - [ボリューム一覧を表示する](#ボリューム一覧を表示する)
    - [ボリュームの詳細情報を表示する](#ボリュームの詳細情報を表示する)
    - [ボリュームを作成する](#ボリュームを作成する)
    - [ボリュームを削除する](#ボリュームを削除する)


## 基本

#### バージョンを表示する
```zsh 
docker version
```

#### システム情報を表示する
```zsh 
docker info
```

#### サブコマンド一覧を表示する
```zsh 
docker help
```

## イメージ管理

### イメージ一覧を表示する
```zsh 
docker images
```

### イメージをダウンロードする
```zsh 
docker pull "イメージ名"
```

### イメージを削除する
```zsh
docker rmi "イメージID"
```

### Dockerfileからイメージをビルドする
```zsh 
docker build -t "イメージ名" -f "Dockerfileパス"
```

## コンテナ管理

### 起動中のコンテナ一覧を表示する
```zsh
docker ps
```

### コンテナ一覧を表示する
```zsh
docker ps -a
```

### コンテナの詳細情報を表示する
```zsh
docker inspect "コンテナ名"
```

### コンテナを作成する
```zsh
docker create --name "コンテナ名" "イメージ名"
```

### コンテナを削除する
```zsh
docker rm "コンテナID"
```

## コンテナ操作

### コンテナを起動する
```zsh
docker start "コンテナID"
```

### コンテナを停止する
```zsh
docker stop "コンテナID"
```

### コンテナを強制停止する
```zsh
docker kill "コンテナID"
```

### コンテナを再起動する
```zsh
docker restart "コンテナID"
```

## コンテナ接続

### コンテナに接続する
```zsh
docker exec -it "コンテナ名" bash
```

### コンテナを停止しないで切断する
```zsh
Ctrl + P + Q
```

### コンテナから切断して停止する
```zsh
exit
```

## ネットワーク管理

### ネットワーク一覧を表示する
```zsh
docker network ls
```

### ネットワークの詳細情報を表示する
```zsh
docker network inspect "ネットワーク名"
```

### ネットワークを作成する
```zsh
docker network create "ネットワーク名"
```

### ネットワークを削除する
```zsh
docker network rm "ネットワーク名"
```

## ネットワーク接続

### コンテナをネットワークに接続する
```zsh
docker network connect "ネットワーク名" "コンテナ名"
```

### コンテナをネットワークから切断する
```zsh
docker network disconnect "ネットワーク名" "コンテナ名"
```

## ボリューム管理

### ボリューム一覧を表示する
```zsh
docker volume ls
```

### ボリュームの詳細情報を表示する
```zsh
docker volume inspect "ボリューム名"
```

### ボリュームを作成する
```zsh
docker volume create "ボリューム名"
```

### ボリュームを削除する
```zsh
docker volume rm "ボリューム名"
```

## DockerCompose

### コンテナを起動する
```zsh
docker-compose up
```

### コンテナを停止して削除する
```zsh
docker-compose down
```

### コンテナ一覧を表示する
```zsh
docker-compose ps
```

### コンテナを停止して削除する
```zsh
docker-compose down
```
Amazon Bedrockでつくる分身AIチャットボット - Part１

# 🟢 はじめに
本記事ではAWSサービスを使用したチャットボット作成方法を記載します。

今回は生成AI関連リソースの学習を主目的としているため、
「まずはとにかく動くものをつくってみよう」のテーマのもと作成しています。
そのため非効率な箇所など多々ありますが、今後機能拡張やコストダウンなどを目指すにあたって少しずつ改良できればと思っています。
こm構築時のキャプチャを載せようと思いましたが膨大になったため、別枠で掲載予定です。
ご意見などあればコメントいただけると幸いです。

# 🤖何をつくるか？
今回作成したいものを整理します。

### 実現したい機能
- テキストベースのチャット形式でやり取りができる  
- ある人物（例：自分、上司、友人）の口調や癖を再現した自然な応答ができる  
- AWSマネージドサービスのみで構成し、インフラレスで運用できる  

### 実装方法テーマ
- Amazon Bedrock の「Continued Pre-training」でモデルをカスタマイズ  
- Amazon Lex V2（Generative AIモード）でチャットボットを構築  
- Lambda で Bedrock API を呼び出して応答生成  
- 学習データは LINE のトーク履歴（事前に加工）  

### 今回はやらない（今後やりたい）こと
- マルチモーダル対応（音声入力・画像認識など）  
- 継続的な自己学習（RAGや動的データ取り込み）  
- LINEやSlackとの連携（Webhookによる通知）  

## 🏠アーキテクチャ概要

```plaintext
[User]
   ↓ テキスト送信
[Amazon Lex V2 (Generative AI)]
   ↓ Lambda 呼び出し
[AWS Lambda]
   ↓ APIリクエスト
[Amazon Bedrock (Custom Claude/Titan)]
   ↓ 応答生成
[AWS Lambda]
   ↓ 応答返却
[Amazon Lex → User]
```
- 会話の入口は Lex（Generative AIモード）
- 応答は Lambda 経由で Bedrock のカスタムモデルを呼び出し生成
- モデルは事前に人物のトーク履歴を元に Continued Pre-training 済み

## 🔨実装方法
### Step 1: トーク履歴を用意（S3へアップロード）
1. LINEのトーク履歴を .txt 形式でエクスポート（LINE PC版 → Keep → 右クリックで保存）
2. 自分の発言だけを抽出（Python等で加工）
3. S3バケットを作成し、data/persona-corpus/ のようなパスでアップロード

### Step 2: Amazon Bedrock で Continued Pre-training
1. Bedrock コンソール → Model Customization → Create Continued Pre-training job
2. モデルは Titan Text G1 または Claude Instant を選択
3. 入力データに上記S3バケットを指定
4. IAMロールを作成（AmazonS3ReadOnlyAccess, AmazonBedrockFullAccess）
5. ジョブ作成後、トレーニングが完了するまで待機（20分〜数時間）
6. モデル一覧に反映される（Training完了後）

### Step 3: Amazon Lex V2（Generative AI モード）でチャットボット構築
1. Lex コンソール → Bot 作成 → Generative Bot を選択
2. モデル選択画面で Bedrock のカスタムモデルを指定
3. 会話スタイルや温度（Creativity）などを調整
4. テスト画面で会話が機能するか確認

### Step 4: Lambda関数でBedrock APIを制御（オプション）
より柔軟に応答生成したい場合は Lambda 関数を用意し、Bedrock API を直接呼び出します。
```
import boto3
import json

client = boto3.client('bedrock-runtime')

response = client.invoke_model(
    modelId='your-custom-model-id',
    body=json.dumps({
        "prompt": "こんにちは！",
        "temperature": 0.7
    })
)

result = json.loads(response['body'].read())
print(result['completion'])
```

## 😕残課題
- LINEトーク履歴の精製には手作業が発生（自動化は要検討）
  ⇨現状は取得したトーク履歴をchatGPTにて整形している。個人情報など含む場合は適さない。
- Bedrock Continued Pre-training はステータス確認がわかりにくい（CloudWatchログ未出力の場合あり）
　⇨度々エラーに悩まされた。。。
- 一部のモデルは Lex Generative AI に非対応（Titanは〇、Mistralは△）
- 冒頭記載の「今回はやらないこと」への対応

## 🟢おわりに
AWSマネージドサービスを活用することで、GPUやインフラの構築を一切せずに、自分の口調を再現する「分身AIチャットボット」 を実現することができました。
会話体モデルをベースに継続学習できる Bedrock の仕組みは、プロンプト制御だけでは難しかった「自然な癖の再現」において非常に効果的です。
今後は LINE連携 や 会話ログの蓄積による自己学習、自分以外のキャラクター再現なども試していきたいです。
商用でも無料でDockerを使う方法（Windows 11）

## 概要：
Docker Desktopを使わず、WSL2のUbuntuにDocker CLIとDocker Engineを直接インストールすることで、完全に無料でDockerを利用できます。
これにより、Dockerのライセンス制限を回避しつつ、商用利用も可能になります。

## 手順（WSL2とUbuntu24.04のインストール）

1. WSL2を有効化
    PowerShellを「管理者権限で」開いて以下を実行：
    ```sh
    wsl --install
    ```

2. UbuntuなどのLinuxディストリビューションをインストール
    Microsoft Storeから「Ubuntu 22.04 LTS」などをインストール。
    インストール後、初回起動でユーザー名とパスワードを設定

5. デフォルトのWSLディストリビューションの確認
    ```sh
    wsl -l -v
    NAME            STATE           VERSION
    * Ubuntu          Stopped         2
      Ubuntu-24.04    Running         2
    ```
    デフォルトでUbuntuが入っているとこういうときがある

6. Ubuntu-24.04 を デフォルト に切り替える方法
    ```sh
    wsl --set-default Ubuntu-24.04
    ```

    今すぐ Ubuntu-24.04 を開く方法（1回限り）
    デフォルトにはせずに、今すぐ Ubuntu-24.04 を起動したいだけなら：
    ```sh
    wsl -d Ubuntu-24.04
    ```

## 手順（WSL2上のUbuntu 24.04 にDockerをインストール）
Ubuntu 24.04は比較的新しいバージョンなので、Docker公式の手順をベースに、動作確認済みの手順で進めます。

1. パッケージの更新と必要パッケージのインストール
    ```sh
    sudo apt update
    sudo apt upgrade -y
    sudo apt install -y ca-certificates curl gnupg lsb-release
    ```

2. Docker公式GPG鍵の追加
    ```sh
    sudo install -m 0755 -d /etc/apt/keyrings
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
      sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
    sudo chmod a+r /etc/apt/keyrings/docker.gpg
    ```

3. Dockerリポジトリを追加
    ```sh
    echo \
      "deb [arch=$(dpkg --print-architecture) \
      signed-by=/etc/apt/keyrings/docker.gpg] \
      https://download.docker.com/linux/ubuntu \
      $(lsb_release -cs) stable" | \
      sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    ```

4. Dockerのインストール
    ```sh
    sudo apt update
    sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
    ```

5. Dockerサービスの起動（WSL内で）
    ```sh
    sudo install -m 0755 -d /etc/apt/keyrings
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
      sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
    sudo chmod a+r /etc/apt/keyrings/docker.gpg
    ```

6. sudoなしでdockerコマンドを使いたい場合（オプション）
    ```sh
    sudo usermod -aG docker $USER
    ```

7. 動作確認
    ```sh
    docker --version
    docker run hello-world
    ```
    Hello from Docker! と表示されれば成功です 🎉
Node.JSで簡易のファイルダウンロードサーバを構築する

Ubuntu環境にnodejsをインストール後、以下のファイルを任意の場所に配置し、コマンド実行することで簡易サーバを起動できる。

```ruby:server.js
const http = require('http');
const fs = require('fs');
const path = require('path');

const hostname = '127.0.0.1';
const port = 3000;

const server = http.createServer((req, res) => {

        const filePath = '.' + req.url;
        const fileName = path.basename(filePath);
        console.log('filePath=' + filePath);
        console.log('fileName=' + fileName);


        fs.readFile(filePath, (err, data) => {
                if (err) {
                        res.writeHead(404, {'Content-Type': 'text/plain'});
                        res.end('File not found...');
                } else {
                        res.writeHead(200, {
                                'Content-Disposition': `attachment; filename=${fileName}`,
                                'Content-Type': 'application/octet-stream'
                        });
                        console.log('File download started!');
                        res.end(data);
                }
        });
});

server.listen(port, () => {
        console.log('start listening on server...');
});
```

※ポート番号は任意の番号を設定できる。

## コマンド実行
以下のコマンドでサーバを起動する。
>node server.js
Ansibleで複数サーバーを鍵認証＆一括管理するまでの手順まとめ

Ubuntu環境でAnsibleを使い、複数のサーバーにSSH鍵認証で接続しながら一括操作できるようにした手順をまとめました。

---

## 📆 環境

- 管理端末：Ubuntu（Proxmox上のVM）
- 対象サーバー：複数のLinuxマシン
- Ansibleバージョン：core 2.16.3

---

## 1. Ansibleのインストール

```bash
sudo apt update
sudo apt install ansible
```

---

## 2. SSH鍵ペアの作成（初回のみ）

```bash
ssh-keygen -t rsa -b 4096
```

Enter連打でOK（`~/.ssh/id_rsa` と `~/.ssh/id_rsa.pub` が作成されます）

---

## 3. 対象サーバーに公開鍵をコピー

対象の各サーバーに対して以下を実行します：

```bash
ssh-copy-id admin@192.168.10.235
ssh-copy-id admin@192.168.10.236
ssh-copy-id admin@192.168.10.237
```

同じ公開鍵を複数のサーバーにコピーできます。

---

## 4. インベントリファイルの作成

`/etc/ansible/hosts` に以下のように記述：

```ini
[web]
192.168.10.235
192.168.10.236

[db]
192.168.10.237

[all:vars]
ansible_user=admin
ansible_ssh_private_key_file=~/.ssh/id_rsa
```

---

## 5. 接続確認（ping）

```bash
ansible all -i /etc/ansible/hosts -m ping
```

以下のような出力が出れば成功：

```json
192.168.10.235 | SUCCESS => { "ping": "pong" }
```

---

## 📆 トラブルシューティング

### ❌ `Permission denied (publickey,password)`
- 接続ユーザーの指定が必要： `-u admin`
- またはパスワード認証用に `--ask-pass` を使う

### ❌ `you must install the sshpass program`
- パスワード認証を使う場合、`sshpass` のインストールが必要：
```bash
sudo apt install sshpass
```

### ❌ `Unable to parse ... as an inventory source`
- hostsファイルのパス指定 or フォーマットのミスが原因

---

## ✨ まとめ

- Ansibleは鍵認証とインベントリで超効率化できる
- pingで疎通確認 → Playbookで実践へステップアップ可能
- SSHの基本をおさえておけば、複数台管理がとても楽になる


以上、どなたかの参考になれば幸いです！
TiDB関連イベント 4月分＆5月さきどり

いよいよ新年度も始まります。
この機会にNewSQL、はじめてみませんか。

PingCAP主催のもの、コミュニティイベントに参加するものの両方を記載しています。WebinarについてはJSTで6:00-24:00に開催されるイベントを記載しています。
また、イベント/社内勉強会など、リクエストに応じてTiDBについてお話し可能です。
リクエストはお気軽に @bohnen ([X/@bohnen](https://twitter.com/bohnen)) までお気軽にご連絡ください。

## ハンズオン：JAWS-UG 名古屋「Dify × Amazon Nova × ベクター検索 ハンズオン」 4/5

https://jawsug-nagoya.connpass.com/event/348603/

告知が遅くてもうキャンセル待ちになってしまっているのですが :cry: 
JAWS-UG 名古屋さんでDify x Amazon Nova x ベクター検索という形でTiDB Serverlessのハンズオンも入っています。

## ウェビナー（英語）：Expert Insights for Success with Distributed SQL 4/17

https://www.pingcap.com/event/expert-insights-for-success-with-distributed-sql-2/

APAC向けのウェビナーで、SaaSアプリケーションでの分散SQLの使い所を元PinterestのDaveさんが語ります。（Daveさんは去年のTiDB User Dayでも講演していただきました）

## ウェビナー：ここがつらいよ分散データベース 4/24

https://pingcap.co.jp/event/20250424-webinar/

JAWS Daysで好評を博したセッションのウェビナー版です。見逃したかたは是非どうぞ。
講師はSolution Architectの小板橋さんです。

## ハンズオン：Serverless Meetup Fukuoka #5 5/10

https://serverless.connpass.com/event/348712/

Serverless Meetupシリーズで AWS Nova x TiDB Serverlessを使ったハンズオンを実施します。
近隣の方はぜひご参加ください！

今年度もよろしくお願いします！
ミーティングで使える英語集

## 1. 挨拶 & アイスブレイク

ミーティングの最初は、軽い挨拶やアイスブレイクで雰囲気を和らげましょう。

Good morning, everyone! How are you today?（おはようございます、皆さん！今日はどうですか？）

How’s everyone doing today?（皆さん、今日の調子はどうですか？）

Hope you’re all doing well!（皆さん元気だといいですね！）


## 2. 参加者の確認

参加者が揃っているかを確認する際のフレーズです。

Is everyone here?（全員揃っていますか？）

Are we all set?（準備は整いましたか？）

Shall we get started?（始めましょうか？）

## 3. ミーティング開始

会議をスムーズに始めるためのフレーズです。

Shall we start the meeting?（ミーティングを始めましょうか？）

Let’s start the meeting!（ミーティングを始めましょう！）

Let’s get started!（始めましょう！）

## 4. 進捗確認

進捗状況を尋ねる際のフレーズを工夫すると、こなれた印象を与えられます。

Firstly, let’s check on our progress. XX-san, how’s your progress?（まずは進捗を確認しましょう。XXさん、進捗はどうですか？）

How’s your implementation going?（実装は進んでいますか？）


implementation は適宜変える。

- Investigation (調査)

- Test (テスト)

- Review (レビュー)

Could you give us a quick update on your task?（タスクの簡単な進捗を教えてもらえますか？）


### 進捗状況に応じた反応

Wow! You already finished it! You’re so fast!（もう終わったんですか！すごく速いですね！）

Ok, you’re doing well! Awesome!（いいですね、順調ですね！素晴らしい！）

It’s ok! Take your time! And let me know if you need a hand! I’ve got your back!（大丈夫ですよ！焦らずやってください！手伝いが必要なら教えてくださいね！）

## 5. 自分の進捗を報告

For me, I’m currently working on XXX.（私は現在XXXに取り組んでいます。）

I’ve been focusing on XXX lately.（最近はXXXに集中しています。）

I just finished XXX, and now I’m moving on to YYY.（XXXを終えたので、YYYに取り掛かっています。）

## 6. 質問されたときの対応

英語で即座に返すのが難しい場合は、後で対応することを伝えると良いでしょう。

I’ll send you the details on Slack later!（詳細は後でSlackに送りますね！）

Let me check and get back to you.（確認して後ほど連絡します。）

That’s a great question! Let me look into it and follow up.（良い質問ですね！調べて後で報告します。）

## 7. 画面共有で説明

英語での説明が難しい場合、画面共有を活用すれば伝わりやすくなります。

Let me explain it with my screen… Can you see my screen?（画面を使って説明しますね… 見えますか？）

Ok, so now, I’m doing this one.（今これをやっています。）

Here’s what I mean. Let me show you.（言いたいことはこれです。お見せしますね。）

## 8. まとめ・終了

ミーティングを終える際のフレーズです。

Do you have anything else to share?（他に共有したいことはありますか？）

Is everything clear so far?（ここまで問題ありませんか？）

If not, we will wrap up the meeting now.（特に問題なければ、ミーティングを終了します。）

That’s all for today’s meeting. Thanks, everyone!（今日のミーティングはこれで終わりです。皆さん、ありがとうございました！）
音楽とPythonを繋げるには(日記)

音楽好きな人にPythonをどうやって紹介するか考えてみよう。Pythonの役立つ記事を挙げて、そこからヒントを得てみるつもりだ。
機械学習や音楽ジャンルの分類、ギターに関連すること、シンセサイザーとかで攻めるのがいいかもしれないね。生成AIを活用すれば、コードを書くのも理解するのも結構簡単だし。どう進めればいいか、雑な文章でまとめてるよ。



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4046871/46e7443b-9f03-4291-9310-4c340e89d142.png)


https://www.youtube.com/watch?v=6jzKpbp8ie0

https://note.com/kotaro_studio/n/nbd13c4c27531


https://qiita.com/yura/items/e5c6e9527215e0e0524a


https://qiita.com/KMASAHIRO/items/cae4dfb0657eec4a2dca



https://qiita.com/NicoTheDog/items/d5612e8a915deac99c43


https://qiita.com/menow2525/items/1d86fcc74e47e300af80

https://keep-learning.hatenablog.jp/entry/2019/08/02/000000

https://qiita.com/a2kiti/items/4449d15e16c1793fd53f

https://youtu.be/2zjMXKgxpmg?si=qsqDah6Olz7S07Hm
blenderチュートリアルにトライしてみた

今月はblenderに挑戦しました。
（以前、何本かチュートリアルをやってみていたんですが、少し期間が開いてしまいかなり記憶が消えていたので………）

今回挑戦したの下記です。
ショートカットなど思い出しつつかわいいものを作りたいという思いが透けて見える選択ですね🐈
ちなみに動画自体30分ですが途中ミス、見返し含め5~6hくらいかかった気がします。
[初心者向け【blender】 ブレンダーで簡単にシルバニアファミリーで人気なペルシャネコの赤ちゃんをモデリング　ショートカット字幕付き【Cycles】
](https://youtu.be/qYux6uMVqEE?feature=shared)


備忘録がてら躓いたところをどう対処したかを記載します。

# 躓きポイント
- 作ったオブジェクトを半分に切るところで差し込んだはずの面も持っていかれる
    - 対象の周は選択していないにもかかわらず巻き込まれて消えていきました
    - これは空白部分の周を選択して「F」で面を差し込んで対応しました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3811577/83909960-6ae4-4190-b7c1-9daf25a94c12.png)

- Mirroを設定したのに対象にならない
    - modifierの先頭にMirrorを一番上に配置するとうまく閉じる旨が動画内でコメントがあったのですが、ミスしてしまい閉じず……（おそらく半分に切る際rotateしたのが原因なのでmirrorの際の回転は危険）
    - 潔く頂点を半分消す前に戻るのが吉
    ※AxisでYも選択すると閉じますが、それをすると耳がキメラ化する惨事となります。また、Gで伸ばそうとしてもきれいには閉じず……

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3811577/56d41f13-04a7-4350-b4cb-b277d73d3b36.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3811577/996a6ab5-782c-4ba5-82f8-7280e39a4783.png)

- ベベルがとがる（写真のようにどうにもまがらない）
    - 編集モード、Aで全選択し、Mで「Merge by Distance」を選択することで重複頂点を削除

とがる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3811577/209556c5-5f36-43a6-86cb-37e3a002f74a.png)

理想
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3811577/46a562e4-0551-498f-9b8d-81d14f362787.png)


# 最終成果物
もう少しシルバニアの解像度を上げてで直せという仕上がりになりましたね！
でもかわいいのでよしとしましょう。
![cat.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3811577/68c493bf-0c5f-4425-b725-f5f6d2ecd321.png)
Amplify Gen2のドキュメントやサンプル まとめ

## はじめに
Amplify Gen2をキャッチアップしやすいように役立つ情報をまとめてみました。

- [ドキュメント](#ドキュメント)
- [サンプル](#サンプル)
- [ワークショップ](#ワークショップ)
- [リポジトリ](#リポジトリ)
- [コミュニティ](#コミュニティ)

## ドキュメント
#### Amplify Docs
https://docs.amplify.aws/

#### Amplify UI
https://ui.docs.amplify.aws/

#### Amplify Hosting

https://docs.aws.amazon.com/amplify/latest/userguide/getting-started.html

## サンプル

#### Storage Browser

https://github.com/aws-samples/sample-amplify-storage-browser

#### Amplify AI
https://github.com/aws-samples/amplify-ai-examples

#### Step Functions
https://github.com/aws-samples/aws-amplify-stepfunctions-example

#### Amazon CloudWatch RUM 
https://github.com/aws-samples/aws-real-user-monitoring-amplifyapps

#### Bedrock
https://github.com/aws-samples/recipe-ai

#### IoT
https://github.com/aws-samples/aws-appsync-iot-core-realtime-example

## ワークショップ

#### Learning Plan Generator with AWS Amplify
https://catalog.us-east-1.prod.workshops.aws/workshops/950b2f47-7b52-46dd-b760-a8144de7f1db/en-US/introduction

## リポジトリ

#### aws-amplify
https://github.com/aws-amplify

#### amplify-backend
https://github.com/aws-amplify/amplify-backend

#### amplify-category-api
https://github.com/aws-amplify/amplify-category-api

#### amplify-js
https://github.com/aws-amplify/amplify-js

#### amplify-ui
https://github.com/aws-amplify/amplify-ui

#### docs
https://github.com/aws-amplify/docs

## コミュニティ
#### Amplify Japan User Group 
https://aws-amplify-jp.github.io/

#### Discord
https://discord.com/invite/2wVQ2D53Na

#### Compass
https://aws-amplify-jp.connpass.com/
`import Foundation` とは？Swift初心者向け記事 

Swiftで開発しているとよく見かけるについて `import Foundation`について調べました。
初心者の方はぜひ参考にしてください。

## 意味

`import Foundation` は **「Foundationフレームワーク（ライブラリ）を使えるようにする」** という意味です。

Swiftには便利な機能がたくさん含まれている標準ライブラリがいくつかあります。その中で `Foundation` は、日付やファイル操作、JSON、データ形式変換など、日常的に必要になる機能を提供しています。

---

##  Foundationで使える主な機能

| 機能名 | 説明 |
|--------|------|
| Date / Calendar | 日付・時間の取得や操作 |
| UUID | 一意なIDの生成 |
| Codable / JSONEncoder / JSONDecoder | JSONデータのエンコード・デコード |
| FileManager | ファイルの保存・読み込み |
| URL | URLの生成や処理 |
| Data | バイナリデータの扱い |

---

## 例1：UUIDの生成

```
import Foundation

let id = UUID()
print(id)
```

`UUID()` を使うためには Foundation のインポートが必要です。

---

## 例2：JSONのエンコード（Codable）

```
import Foundation

struct User: Codable {
    var name: String
    var age: Int
}

let user = User(name: "太郎", age: 25)
let data = try JSONEncoder().encode(user)
```

JSONへの変換処理は `Foundation` の機能に含まれています。

---
## 要はこんな時に使う
次のようなことをしたいときには `Foundation` が必要です。

- データの保存や読み込み（FileManager）
- JSONとのやり取り（Codable）
- UUIDなどの識別子生成
- 日時の処理

##  import SwiftUIを書けば十分？

:::note
以下内容は、@nak435 さんに教えて頂きました。ありがとうございます。
:::
`import SwiftUI` は `@_exported import Foundation` という形で `Foundation` を読み込んでいます。これは「SwiftUIをインポートしたときに、その内部で使っている`Foundation`も一緒に見えるようにする」という意味になります。

つまり `import SwiftUI` をすると、間接的に `Foundation` もインポートされていることになり、明示的な `import Foundation` を書かなくても、`UUID` や `DateFormatter` などが使えるというわけです。


:::note
ちなみに、ChatGPTさんにも意見を伺ったところ、このような見解でした。

- **明示的にFoundationの機能を使うと分かっている場合は `import Foundation` を書いたほうが可読性が上がる**
- 他のフレームワーク（UIKitなど）だけを使う場合は `Foundation` を明示的にインポートする必要がある
- **SwiftUI以外では `Foundation` は自動でインポートされない**ため、依存関係が分かりづらくなることを防ぐためにも書いておくのが安全
:::




---

##  まとめ

- `import Foundation` は便利な基本機能を使うためのおまじない
- JSON、ファイル、日時などを扱うなら必須
- SwiftUIと一緒に使うなら書かなくてもいい。【可読性のため、書くのはアリ】

---
基本情報技術者試験 2回目で合格した話

# はじめに
プログラマになり日々の仕事にあっぷあっぷですが
メモがてら書きます。

今回2回目の基本情報受験でギリギリぎ合格を果たしたので、
勉強したこと・方法などをまとめていこうと思います。

# 基本情報技術者試験
基本情報技術者試験（略称 FE 試験）は、情報処理技術者としての基礎的な知識やスキルを評価する試験です。

試験の詳細は、こちらの記事がわかりやすかったです。

https://qiita.com/hidemaru-jp/items/bca547bf03fff96f6020

# １回目の受験
【勉強時間】
A試験：1週間
B試験：2週間
※仕事をしていない時期なので、時間はたっぷり使えました。

【点数】
A試験：590点
B試験：590点
ギリギリ不合格となりました。

# ２回目の受験結果
1回目からかなり時間が経っていたので、インプットからやり直しでした…
【勉強時間】
A試験：3週間
B試験：3日間
※仕事をしながら、合間に勉強しました。

【点数】
A試験：610点
B試験：620点
ギリギリ合格となりました。

# 勉強法
### YouTube
【基本情報技術者試験YouTuber】すーさんの動画をひたすら見る
B試験は、ほとんどこの動画の問題しか解いてません！

https://youtu.be/oqaBEnhIxk0?si=tmGx_TqF9CXSMOcg

https://youtu.be/wFpyeWto8Og?si=YMl1tm75Hz0awO0C

### Notion
Notionでスケジュールを組んで、そこに目次を作る

![スクリーンショット 2025-03-31 21.11.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3782860/3a3dda24-acae-4f13-8302-aabaa0784cfd.png)

![スクリーンショット 2025-03-31 21.13.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3782860/3222fc39-0f6b-40be-a354-ab25f7511269.png)


学習した内容をスクショでもいいので、Notionにまとめてる

![スクリーンショット 2025-03-31 21.04.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3782860/17d6c3d5-56fb-4a83-b062-5d84103565ba.png)

![スクリーンショット 2025-03-31 21.05.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3782860/a27fefef-2a5a-4b22-9adf-9db183c5f881.png)

### 合格教本・過去問題集
YouTubeで足りない知識を合格教本で補い、過去問題集や演習問題を解く

![IMG_9185.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3782860/c3cad48f-fe90-44c4-8a29-e58034ea3de0.jpeg)

### 過去問道場
基本情報を勉強している人なら誰もが知っている過去問道場
私も大変お世話になりました！

https://www.fe-siken.com/fekakomon.php

あとはひたすら過去問を解きまくるだけです！

# さいごに
インプットはさっさと終わらせて、アウトプットに入ったほうがいいです。わからなかった問題があれば、その都度インプットするようにしました。

勉強方法が参考になりましたら幸いです！
【Tips】EdgeでInternetExplorer（IEモード）を使う

## IntenetExplorerが使いたい！
InternetExplorerで動作検証がしたいのに、IEが入っているPCがない！
そんなときはとりあえずこれを使いましょう

IEモードではInternetExplorerで使われるレンダリングエンジンTridentを使うことができ
（ActiveXなどIE固有の技術は除き）ほぼ同じようにページが表示できるようです

# 設定手順
1. Edgeを開き、ウィンドウ右上の［…］を押下して設定を押下する

2. 左ペインで［既定のブラウザー］を押下して、Internet Explorer モード（IDモード）でサイトの再読み込みを許可 で［許可］を選択する
![{33E51692-F386-457D-9AFA-E2F99A04832C}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3756373/6cd3fe7e-6343-4f74-aad5-2a223ebb6467.png)

3. IEモードで表示したいページを開き、ウィンドウ右上の［…］を押下して［Internet Explorer モードで再読み込み］を押下する
![{21C87015-AB77-4E3A-BDA0-0A933C52967C}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3756373/6cece703-4603-4774-acd0-bef52ef99fca.png)
Array.from() でループ不要！ (A, B) をN回出力するスマートな方法

Paizaの問題を解いていたら、 `(A, B)` を`N`回出力するだけなのに、もっとスッキリ書ける方法があった！ `for`ループを使うのもアリだけど、`Array.from()` を使うと一発で解決できるぞ！

問題:`(A, B)` を`N`回出力せよ！

📌 入力例
```
3 5 7　　// N A B
```
📌 出力例
```
(5, 7), (5, 7), (5, 7)
```
👉 `N`回 `(A, B)` を出力し、各ペアは カンマ + 半角スペース で区切る。

https://paiza.jp/works/mondai/stdout_primer/stdout_primer__specific_format_step2


## <br>最初のNGコード: `for`ループでゴリ押し
```js
const rl = require('readline').createInterface({ input: process.stdin });

rl.on('line', (input) => {
    const [N, A, B] = input.split(" ").map(Number);
    const nums = [];
    for(let i = 0; i < N; i++){
        nums.push(`(${A}, ${B})`);
    }
    console.log(nums.join(", "));
});
```
💡 問題点
- `for`ループで `N` 回 `push()` するのがちょっと冗長
- 変数 `nums` を使わずにもっと短く書ける

## <br>改善版: `Array.from()` でループを消す！
```js
const rl = require('readline').createInterface({ input: process.stdin });

rl.on('line', (input) => {
    const [N, A, B] = input.split(" ").map(Number);
    console.log(Array.from({ length: N }, () => `(${A}, ${B})`).join(", "));
});
```
改善ポイント🚀
✅ `Array.from()` で配列を1行で生成
✅ ループ不要でスッキリ！
✅ 可読性UP！ 余計な変数なし

## <br>気づきメモ📝
- `Array.from({ length: N })` は長さ`N`の配列を作る
- マッピング関数 `() => \(${A}, ${B})`` ` で各要素をセット

    ループを書かなくても、スマートに配列を作れる！

## <br>まとめ

✔ `for`ループより `Array.from()` を使うと短く書ける
✔ 繰り返し処理はループ以外の方法も考えよう
✔ 可読性が上がるとバグも減る！

こういう小さな工夫が、"書きやすくて読みやすい" コードにつながるぞ！💡

<br>[僕の失敗談と解決話！](https://paizabeginner.wordpress.com/2025/03/31/paiza%e3%81%a7%e5%9f%ba%e6%9c%ac%e3%83%9e%e3%82%b9%e3%82%bf%e3%83%bc-a-b-%e3%82%92n%e5%9b%9e%e5%87%ba%e5%8a%9b%ef%bc%81%e3%83%ab%e3%83%bc%e3%83%97%e3%81%aa%e3%81%97%e3%81%a7%e3%82%b9%e3%83%9e/)
自己証明書を作成してHTTPSでWebサイトにアクセスする

# 背景
HTTPSを利用するWebサイトを構築した

クライアント側でブラウザからサイトを立ち上げたところ下のような警告ページが表示された
このままでもアクセスできるが、アドレスバーに「セキュリティ保護なし」と表示されていて気になる…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3756373/92542447-03cc-bc28-e53a-fc2f2e9e3938.png)

# 原因
接続しようとしているサイト（サーバー）が信頼できるものではなく、なりすましや悪意のあるサイトである可能性があるために警告が表示されている。
今回の場合、testserver1というサーバーが本当にアクセスしたいtestserver1であるという保証がない、という警告である。

# 対策
接続しようとしているサイトが正しいものであることを証明する必要がある。
これがサーバー証明書であり、サーバーが意図したものであることの証明と、外部から傍受されないように暗号化した通信をするために用いられている。
正しいものであるかを証明するため、証明書は認証局によって統括されている。認証局のお墨付きがあれば正しいものとして判断できる。

なお、認証局のものでなくとも、自分で証明書を発行することは可能であり、自己証明書（オレオレ証明書）と呼ばれる。
認証局による証明がされていないため、不特定多数に向けたサイトには向かないが、検証や利用者が限定されるサイトなどの通信には利用できる。
今回はこの自己証明書を使ってこの警告ページが表示されないようにすることを目的とする。

# 実際に使ってみる
### 1. 証明書の発行
自己証明書を作成する
1. IISマネージャーを開き、サーバーの機能ビューで[IIS] - [サーバー証明書] をダブルクリックする
![{9232A2B7-8F57-4105-BD18-E6DDD75D738D}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3756373/0b92a2e8-e24c-4ccc-b745-5b9c53762117.png)

2. 右側の [操作] ペインで「自己署名入り証明書の作成…」を押下する
![{C5B0DD34-0C31-4BB8-8A1D-7A5629A64709}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3756373/330ea00e-14eb-40e0-8a30-a039dcf3c7cb.png)

3. 証明書のフレンドリ名を入力して［OK］ボタンを押下する
![{C1AB9C98-F16C-432C-BF21-82FD07BD07ED}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3756373/f660882b-706c-4d0f-904b-912b23277284.png)

4. サーバー証明書の一覧に作成した証明書が表示されていることを確認する
※有効期限はデフォルトで1年間に設定される模様
![cert1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3756373/a2b5fe7c-4d9f-4829-93b2-3835dfcf2172.png)

### 2. 証明書のバインド
作成した自己証明書をWebサイトにアクセスした際に利用する証明書として登録する
1. アクセス（HTTPS通信）したいWebサイトを [接続]ペインで選択し、[操作]ペインの［バインド］を押下する

2. サイトバインドウィンドウでhttpsの行を選択して［編集］ボタンを押下する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3756373/fa6cdb6e-acbd-4a80-ac62-58fb4ecb5a4a.png)

3. SSL証明書で先ほど作成した証明書を選択して［OK］ボタンを押下する
![{FD8A38C6-CDB7-4A67-846D-42F1F58A09DD}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3756373/697c1070-2061-4b90-bfb3-d1b91d44962c.png)

### 3. 証明書のインポート
作成した証明書をクライアント側の端末にインストールする
※認証局が発行した証明書の場合は不要

1. 1-4のサーバー証明書の一覧で作成した証明書を右クリックし、[エクスポート]を選択する

2. エクスポート先のパスと任意のパスワードを設定して証明書をエクスポートする
![{0CA35D01-C186-4C18-A217-E4F3BA0CA351}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3756373/cc8dd1f8-2324-4d80-8a81-4ede06ee3060.png)

3. アクセスする端末でエクスポートした証明書をダブルクリックする

4. 指示に従って証明書をインポートする
![{7BEF22F0-6EE4-42A6-A1D1-2B920F4F44A5}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3756373/7ed0fe26-300d-494d-a909-2782703cae02.png)


### 4. アクセスしてみる
1. HTTPSでWebサイトにアクセスする

![{9326DEA6-C936-42E7-AF8A-380049568F22}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3756373/8c7571e3-bc9b-4178-bf38-d9d9205f0327.png)
再起クエリの性能改善

# 背景
SQLserverでとあるスカラ関数を作成して性能検証していたところ実行に思いのほか時間がかかった
関数では再帰クエリを使用しており、パフォーマンス改善を実施した

# 関数の概要
 - 引数1（一般職ユーザー）が引数2（管理職ユーザー）の部下であるか確認するための関数
 - ユーザーは1つ以上の組織に所属している
 - 組織は階層情報を持ち、各組織データに親組織データを持つ
 - 引数2のユーザーの組織に所属するユーザーとさらにその下部組織に所属するユーザーをWITH句を使って再帰的に取得し、そのユーザーの中に引数1が含まれることを確認する

例えば下のような組織の場合、下記のような結果になる
【TRUE】
引数1：捜査第一課のCさん
引数2：警視庁直下のAさん

【FALSE】
引数1：刑事部直下のBさん
引数2：捜査第一課のDさん

![{B6A41D45-7EFA-4EF3-8B5D-2282DCDB2DC7}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3756373/e3d05c85-b1ad-4bf0-8a99-b7c620a45fba.png)

# 課題
管理職ユーザーを起点に下部組織のすべてのユーザーを取得し、その中に指定したユーザーがいるかを確認していたため、下部組織が多くなるほど取得するユーザー件数が多くなり処理時間が長くなっていた
例えば1組織10名のユーザーがいた場合、警視庁直属のAさんの場合40人のユーザを読み込む必要があった

# やったこと
### 解決策①
管理職ユーザーを起点にするのではなく、一般職ユーザーを起点に検索する方法に変更する
所属組織の上位の組織のみを検索よいため、捜査第一課のCさんの場合、30人のユーザーを読み込めばよくなる
分かりやすく示すため例として記載した組織数は少ないが、実際に運用されている組織は1組織10以上の下部組織を持っているため読み込むユーザー数の違いが大きくなることが見込まれる
再帰クエリ自体はなくならないため、性能改善は限定的である可能性がある

### 解決策②
あらかじめ再帰部分をビューもしくはテーブルに保存することで、性能改善のボトルネックとなっている再帰クエリ自体を利用しないようにする
今回の場合は組織階層をテーブルやビューで保持しておくようにすることで再帰クエリのコストがなくなるため性能の向上が見込まれる
再帰クエリを実行しない分、①より大幅な性能改善が見込めるもののテーブルやビューの設計が必要になる

### 解決策③
適切なインデックスを作成する
クエリ実行計画を確認し、インデックスが適切に利用されるよう修正する

# まとめ
クエリの性能改善ではインデックスやテーブルのチューニングにフォーカスしがちだったが、クエリそのものの見直しも有効である