はじめに
こんにちは、はじめまして。
TechJapan合同会社の興野(きょうの)です。
この度、「学習型ラジアルメニュー検索支援システム」 の特許を出願しました。
(2024年11月10日出願 特願2025-189784)
本記事では、開発の背景から技術的なチャレンジ、そして特許戦略まで、エンジニア視点で詳しく解説します。
目次
- 解決したい課題
- Dango searchとは何か
- 技術的なアプローチ
- 実装のポイント
- 先行技術との差別化
- 特許戦略
- 今後の展開
1. 解決したい課題
1.1 既存の検索UIが抱える問題
私たちは賃貸物件検索サイト、RooMii( https://www.roomii.jp/ )
の運営もしているので、不動産検索の具体的な課題について考えていました。
従来のフォームUI:
┌─────────────────┐
│ エリア: [選択▼] │
│ 価格帯: [選択▼] │
│ 間取り: [選択▼] │
│ 築年数: [選択▼] │
│ 駅距離: [選択▼] │
│ ⋮ │
│ (さらに10項目) │
│ [検索] │
└─────────────────┘
問題点:
- スクロールが多い(平均20回以上)
- 全体像が把握できない
- よく使う条件も毎回同じ位置
- 検索結果が出るまで件数不明
1.2 デジタル・インクルージョンの課題
高齢者:
- 文字が小さくて見えない
- スクロールで迷子になる
- チェックボックスが押しにくい
視覚障害者:
- コントラストが低い
- ボタンのサイズが不十分
上肢障害者:
- 画面端まで指が届かない
- 細かいタップ操作が困難
→ 70歳以上の70%がスマホ検索で挫折
(ぶっちゃけ、70歳以上でWebをりようして賃貸探す人は少ないです笑)
2. Dango searchとは何か
2.1 コンセプト
「誰もが迷わず使える検索UI」
文字入力を排除し、タップだけで複雑な検索を実現。
2.2 UIの特徴
[条件A]
↑
[条件D] ← [検索] → [条件B]
↓
[条件C]
ラジアルメニュー形式:
- 画面中心に検索ボタン
- 周囲に条件が放射状に配置
- タップで階層を深掘り
学習機能:
- ユーザーの選択履歴を分析
- よく使う条件を上部に優先配置
- 使うほど速くなる
リアルタイムフィードバック:
- 条件選択のたびに件数表示
- 絞り込み過多/過少を即座に判断
Demo動画(ショート)
3. 技術的なアプローチ
3.1 アーキテクチャ概要
┌─────────────────┐
│ Frontend (Web) │
│ - React/HTML5 │
│ - タッチイベント │
└─────────────────┘
↓
┌─────────────────┐
│ Backend (GCP) │
│ - Firebase │
│ - BigQuery │
│ - Cloud Func │
└─────────────────┘
↓
┌─────────────────┐
│ Database │
│ - 物件DB │
│ - 学習モデル │
└─────────────────┘
3.2 ラジアルメニューの数学的基礎
配置角度の計算:
// N個のボタンを円周上に等間隔配置
const calculateAngle = (index, total) => {
return (360 / total) * index - 90; // -90°で12時方向スタート
};
// 座標の算出
const calculatePosition = (angle, radius, centerX, centerY) => {
const rad = angle * (Math.PI / 180);
return {
x: centerX + radius * Math.cos(rad),
y: centerY + radius * Math.sin(rad)
};
};
最適な配置半径:
- スマホ: 130-160px (親指の可動範囲)
- タブレット: 200-250px
- デスクトップ: 300px以上
3.3 学習アルゴリズムの概要
優先度スコアの計算:
優先度スコア =
選択回数 × 0.5 +
直近30日の選択回数 × 0.3 +
検索成功回数 × 0.2
コンテキスト認識:
- 時間帯 (平日夜 vs 週末昼)
- デバイス種別
- ユーザー属性
配置最適化:
- 上位3-4項目を0°〜90°に配置
- 到達しやすい位置に頻出条件
4. 実装のポイント
4.1 モバイルUXの最適化
タッチ操作の制御:
.menu-item {
touch-action: manipulation; /* ダブルタップズーム無効化 */
user-select: none; /* テキスト選択防止 */
}
セーフエリア対応:
body {
padding-top: env(safe-area-inset-top);
padding-bottom: env(safe-area-inset-bottom);
}
アクセシビリティ:
- 最小タップ領域: 72×72px (WCAG準拠)
- 中心ボタン: 112×112px (親指操作に最適)
4.2 データ構造の設計
階層構造:
const searchTree = {
id: 'root',
label: '検索',
children: [
{
id: 'kanto',
label: '関東',
children: [
{ id: 'tokyo', label: '東京', children: [...] },
{ id: 'kanagawa', label: '神奈川', children: [...] }
]
}
]
};
選択状態の管理:
// Mapで複数条件を管理
const selectedConditions = new Map();
selectedConditions.set('price_5to6', '5〜6万円');
selectedConditions.set('layout_1k', '1K');
selectedConditions.set('station_shibuya', '渋谷駅');
4.3 リアルタイム検索の実装
クエリの動的生成:
const buildQuery = (conditions) => {
const filters = [];
conditions.forEach((label, id) => {
if (id.startsWith('price_')) {
filters.push({ field: 'price', operator: 'range', value: ... });
} else if (id.startsWith('layout_')) {
filters.push({ field: 'layout', operator: 'eq', value: ... });
}
});
return { filters, logic: 'AND' };
};
件数の高速取得:
- 全件スキャンではなくインデックスを活用
- 目標レスポンス: 100ms以内
5. 先行技術との差別化
5.1 既存の円形UIとの比較
| 項目 | Apple Radial Menu | MS Dial | Dango search |
|---|---|---|---|
| 配置 | 固定 | 固定 | 学習で動的 |
| 選択 | 単一 | 単一 | 複数(AND) |
| 用途 | 一般メニュー | ツール選択 | 検索特化 |
| フィードバック | なし | なし | リアルタイム件数 |
5.2 FTO(Freedom to Operate)調査の結果
主要な先行特許:
- US8245156B2 (Apple): ラジアルメニューの基本構造
- US10831337B2 (Apple): 予測ベースのUI最適化
- US10198148B2 (Microsoft): コンテキスト認識型メニュー
差別化ポイント:
-
検索プロセスへの特化
- 複数条件の同時選択
- AND検索の実現
-
Map構造による状態管理
- 先行技術にはない実装方法
-
リアルタイム件数表示
- 検索の都度フィードバック
-
デジタル包摂を主目的とした設計
- 文字入力の排除
- アクセシビリティ最優先
6. 特許戦略
6.1 出願のタイミング
なぜ今出願したのか:
- プロトタイプで実装可能性を実証
- 先行技術調査で差別化を確認
- ビジネス展開の前に権利確保
6.2 請求項の構成
基本構成(請求項1):
- ラジアルメニュー表示
- 学習による配置最適化
- リアルタイム件数表示
- Map構造による状態管理
応用展開(請求項2-14):
- 不動産、求人、EC等への応用
- 階層構造の実装
- 方法、プログラムのクレーム
6.3 進歩性の立証戦略
従来技術との本質的な違い:
効率化 ≠ インクルージョン
既存技術:
- 「健常な若者がさらに速く使える」
本発明:
- 「これまで使えなかった人が使えるようになる」
非自明性の根拠:
- 課題設定が先行技術の範囲外
- 組み合わせの動機づけが不明
- 顕著な効果(排除されていた層へのアクセス)
7. 今後の展開
7.1 技術ロードマップ
2025年Q1:
- 学習機能の実装完了
- RooMiiでの正式リリース
2025年Q2:
- A/Bテストによる効果検証
- ユーザーフィードバックの収集
2025年Q3:
- BtoB展開開始
- 製造業・医療分野への応用
7.2 改善の計画
- コンテキスト認識の強化
- 音声UIとの統合
- エラーチェック機構
目標: 5-10件の特許ポートフォリオ
7.3 ビジネス展開
BtoC (RooMii):
- 不動産検索プラットフォーム
- 月額課金モデル
BtoB (ライセンス):
- 製造業: 部品検索システム
- 医療: 機器・薬品検索
- 人材: 求人マッチング
まとめ
Dango searchは、単なる「便利なUI」ではありません。
「デジタル技術から排除されていた人々に、アクセスを提供する」
というミッションを持った技術です。
特許出願はゴールではなくスタートライン。
これから、実装→検証→展開のサイクルを回していきます。
付録: プロトタイプのデモコード(抜粋)
ラジアルメニューの描画
function renderMenu(node, radius = 160) {
const items = node.children || [];
const container = document.getElementById('menu-items');
items.forEach((item, index) => {
const angle = calculateAngle(index, items.length);
const pos = calculatePosition(angle, radius, 180, 180);
const button = createButton(item, pos);
container.appendChild(button);
// アニメーション
setTimeout(() => {
button.classList.add('visible');
}, index * 50);
});
}
function createButton(item, position) {
const button = document.createElement('button');
button.className = 'menu-item';
button.style.transform = `translate(${position.x}px, ${position.y}px)`;
button.textContent = item.label;
button.addEventListener('click', () => {
handleItemClick(item);
});
return button;
}
学習機能のスケルトン
class SearchOptimizer {
constructor() {
this.history = [];
this.priorityScores = new Map();
}
recordSelection(conditionId) {
this.history.push({
id: conditionId,
timestamp: Date.now()
});
}
calculatePriority(conditionId) {
const total = this.history.filter(h => h.id === conditionId).length;
const recent = this.history
.filter(h => h.id === conditionId &&
Date.now() - h.timestamp < 30 * 24 * 60 * 60 * 1000)
.length;
return total * 0.5 + recent * 0.3;
}
getOptimizedOrder(items) {
const scored = items.map(item => ({
...item,
priority: this.calculatePriority(item.id)
}));
return scored.sort((a, b) => b.priority - a.priority);
}
}
最後まで読んでいただき、ありがとうございました!
この技術に興味を持っていただけた方、ぜひLGTMやストック、コメントをお願いします 🙏