@aiquants/fuzzy-search
Version:
Advanced fuzzy search library with Levenshtein distance, n-gram indexing, and Web Worker support
1 lines • 112 kB
Source Map (JSON)
{"version":3,"sources":["../../src/types/index.ts","../../src/worker/common.ts","../../src/worker/indexWorker.ts"],"sourcesContent":["/**\n * @module types/index\n * @description Core types for the fuzzy search library.\n * @description あいまい検索ライブラリのコア型定義。\n */\n\n// ===== Basic Configuration Types =====\n\n/**\n * @interface FuzzySearchOptions\n * @description Configuration options for fuzzy search functionality.\n * @description あいまい検索機能の設定オプション。\n */\nexport interface FuzzySearchOptions {\n /**\n * @property {number} threshold - Similarity threshold (0.0-1.0).\n * @description 類似度の閾値。この値以上のスコアを持つアイテムが結果に含まれます。\n */\n threshold: number\n\n /**\n * @property {boolean} caseSensitive - Whether to perform case-sensitive search.\n * @description 大文字小文字を区別するかどうか。true の場合、区別して検索します。\n */\n caseSensitive: boolean\n\n /**\n * @property {number} learningWeight - Learning weight for user behavior (0.0-2.0).\n * @description ユーザーの選択行動に基づく学習による重み付け。1.0より大きいと学習効果が強まります。\n */\n learningWeight: number\n\n /**\n * @property {number} debounceMs - Debounce time in milliseconds.\n * @description 検索入力のデバウンス時間(ミリ秒)。連続入力時の不要な検索処理を防ぎます。\n */\n debounceMs: number\n\n /**\n * @property {'and' | 'or'} multiTermOperator - Logical operator applied to space-separated query terms.\n * @description スペース区切りのクエリ語に適用する論理演算子。\n */\n multiTermOperator: \"and\" | \"or\"\n\n /**\n * @property {boolean} autoSearchOnIndexRebuild - Whether to trigger a search immediately after the index is rebuilt.\n * @description インデックス再構築直後に自動的に検索を実行するかどうか。\n */\n autoSearchOnIndexRebuild: boolean\n\n /**\n * @property {Record<string, number>} customWeights - Custom field weights for scoring.\n * @description 特定のフィールドに対するカスタムの重み設定。スコアリングに影響します。\n */\n customWeights: Record<string, number>\n\n /**\n * @property {number} ngramSize - N-gram size for indexing (default: 2).\n * @description インデックス作成に使用する N-gram のサイズ。通常は2または3が使われます。\n */\n ngramSize: number\n\n /**\n * @property {number} minNgramOverlap - Minimum n-gram overlap for candidate filtering.\n * @description 候補フィルタリングのための最小 N-gram 重複数。\n */\n minNgramOverlap: number\n\n /**\n * @property {'score' | 'relevance' | 'original'} sortBy - Sort results by field.\n * @description 検索結果のソート基準。'score' (類似度スコア)、'relevance' (関連性)、'original' (元の順序) から選択します。\n */\n sortBy: \"score\" | \"relevance\" | \"original\"\n\n /**\n * @property {'asc' | 'desc'} sortOrder - Sort order (ascending or descending).\n * @description ソート順序 (昇順または降順)。\n */\n sortOrder: \"asc\" | \"desc\"\n\n /**\n * @property {boolean} enableIndexFiltering - Enable index-based filtering stage.\n * @description インデックスベースのフィルタリングステージを有効にするかどうか。\n */\n enableIndexFiltering: boolean\n\n /**\n * @property {boolean} enableLevenshtein - Enable Levenshtein distance calculation stage.\n * @description レーベンシュタイン距離計算ステージを有効にするかどうか。\n */\n enableLevenshtein: boolean\n\n /**\n * @property {'index-first' | 'levenshtein-first' | 'balanced'} parallelSearchStrategy - Parallel search strategy.\n * @description 並列検索の戦略。'index-first' (インデックス優先)、'levenshtein-first' (レーベンシュタイン優先)、'balanced' (バランス) から選択します。\n */\n parallelSearchStrategy: \"index-first\" | \"levenshtein-first\" | \"balanced\"\n\n /**\n * @property {object} [workerUrls] - Custom Worker URLs for external hosting.\n * @description 外部ホスティング用のカスタム Worker URL。\n */\n workerUrls?: {\n /**\n * @property {string} [indexWorker] - URL for the index worker.\n * @description Index Worker の URL。\n */\n indexWorker?: string\n /**\n * @property {string} [levenshteinWorker] - URL for the levenshtein worker.\n * @description Levenshtein Worker の URL。\n */\n levenshteinWorker?: string\n }\n\n /**\n * @property {object} [indexWorkerOptions] - Index Worker specific parameters.\n * @description Index Worker 固有のパラメータ。\n */\n indexWorkerOptions?: {\n /**\n * @property {IndexStrategy} [strategy] - Index Worker search strategy ('fast' | 'accurate' | 'hybrid').\n * @description Index Worker の検索戦略。\n */\n strategy?: IndexStrategy\n /**\n * @property {number} [threshold] - Similarity threshold for Index Worker (0.0-1.0).\n * @description Index Worker 用の類似度閾値。\n */\n threshold?: number\n /**\n * @property {number} [ngramOverlapThreshold] - N-gram overlap threshold ratio (0.0-1.0).\n * @description N-gram 重複閾値の比率。\n */\n ngramOverlapThreshold?: number\n /**\n * @property {number} [minCandidatesRatio] - Minimum candidates ratio for fast search (0.0-1.0).\n * @description 高速検索用の最小候補比率。\n */\n minCandidatesRatio?: number\n /**\n * @property {number} [maxCandidatesRatio] - Maximum candidates ratio to trigger filtering (0.0-1.0).\n * @description フィルタリングを発動するための最大候補比率。\n */\n maxCandidatesRatio?: number\n /**\n * @property {number} [jaroWinklerPrefix] - Jaro-Winkler prefix scaling factor (0.0-0.25).\n * @description Jaro-Winkler アルゴリズムの接頭辞スケーリング係数。\n */\n jaroWinklerPrefix?: number\n /**\n * @property {number} [maxResults] - Maximum number of results for Index Worker.\n * @description Index Worker 用の最大結果数。\n */\n maxResults?: number\n /**\n * @property {number} [relevanceFieldWeight] - Weight for matched field count in relevance score (0.0-1.0).\n * @description relevance スコア計算時のマッチフィールド数の重み。\n */\n relevanceFieldWeight?: number\n /**\n * @property {number} [relevancePerfectMatchBonus] - Bonus for perfect match in relevance score (0.0-1.0).\n * @description relevance スコア計算時の完全一致ボーナス。\n */\n relevancePerfectMatchBonus?: number\n }\n\n /**\n * @property {object} [levenshteinWorkerOptions] - Levenshtein Worker specific parameters.\n * @description Levenshtein Worker 固有のパラメータ。\n */\n levenshteinWorkerOptions?: {\n /**\n * @property {number} [threshold] - Similarity threshold for Levenshtein Worker (0.0-1.0).\n * @description Levenshtein Worker 用の類似度閾値。\n */\n threshold?: number\n /**\n * @property {number} [lengthSimilarityThreshold] - Length-based similarity threshold for early rejection.\n * @description 長さベースの類似度閾値(早期リジェクション用)。\n */\n lengthSimilarityThreshold?: number\n /**\n * @property {number} [partialMatchBonus] - Partial match bonus score.\n * @description 部分一致が検出された場合に加算されるボーナススコア。\n */\n partialMatchBonus?: number\n /**\n * @property {number} [lengthDiffPenalty] - Length difference penalty ratio.\n * @description 文字列長の差によるペナルティの比率。\n */\n lengthDiffPenalty?: number\n /**\n * @property {number} [maxResults] - Maximum number of results for Levenshtein Worker.\n * @description Levenshtein Worker 用の最大結果数。\n */\n maxResults?: number\n /**\n * @property {number} [relevanceFieldWeight] - Weight for matched field count in relevance score (0.0-1.0).\n * @description relevance スコア計算時のマッチフィールド数の重み。\n */\n relevanceFieldWeight?: number\n }\n}\n\n/**\n * @type PartialFuzzySearchOptions\n * @description Partial options for initializing fuzzy search. Allows overriding a subset of the default options.\n * @description あいまい検索初期化用の部分オプション。デフォルトオプションの一部を上書きできます。\n */\nexport type PartialFuzzySearchOptions = Partial<FuzzySearchOptions>\n\n/**\n * @const DEFAULT_FUZZY_SEARCH_OPTIONS\n * @description Default options for fuzzy search. Used when no options are provided.\n * @description あいまい検索のデフォルトオプション。オプションが指定されなかった場合に使用されます。\n */\nexport const DEFAULT_FUZZY_SEARCH_OPTIONS: FuzzySearchOptions = {\n threshold: 0.4,\n caseSensitive: false,\n learningWeight: 1.2,\n debounceMs: 300,\n multiTermOperator: \"and\",\n autoSearchOnIndexRebuild: true,\n customWeights: {},\n ngramSize: 2,\n minNgramOverlap: 1,\n sortBy: \"relevance\",\n sortOrder: \"desc\",\n enableIndexFiltering: true,\n enableLevenshtein: true,\n parallelSearchStrategy: \"balanced\",\n indexWorkerOptions: {\n strategy: \"hybrid\",\n threshold: 0.4,\n ngramOverlapThreshold: 0.3,\n minCandidatesRatio: 0.1,\n maxCandidatesRatio: 0.5,\n jaroWinklerPrefix: 0.1,\n maxResults: 1000,\n relevanceFieldWeight: 0.2,\n relevancePerfectMatchBonus: 0.1,\n },\n levenshteinWorkerOptions: {\n threshold: 0.3,\n lengthSimilarityThreshold: 0.1,\n partialMatchBonus: 0.1,\n lengthDiffPenalty: 1.0,\n maxResults: 1000,\n relevanceFieldWeight: 0.15,\n },\n}\n\n// ===== Search Result Types =====\n\n/**\n * @interface SearchResultItem\n * @description Represents an individual search result item with metadata.\n * @description メタデータを含む個別の検索結果アイテムを表します。\n * @template T - The type of the original item.\n */\nexport interface SearchResultItem<T = unknown> {\n /**\n * @property {T} item - The original item from the search dataset.\n * @description 検索データセットの元のアイテム。\n */\n item: T\n\n /**\n * @property {number} score - Final similarity score (0.0-1.0+). May exceed 1.0 in Relevance mode due to bonuses.\n * @description 最終的な類似度スコア (0.0-1.0+)。Relevance モードではボーナスにより 1.0 を超える場合があります。\n */\n score: number\n\n /**\n * @property {number} baseScore - Base similarity score before any adjustments (0.0-1.0).\n * @description 調整前の基本類似度スコア (0.0-1.0)。Relevance モードの重み付け前の値です。\n */\n baseScore: number\n\n /**\n * @property {string[]} matchedFields - Fields that matched the search query.\n * @description 検索クエリにマッチしたフィールドのリスト。\n */\n matchedFields: string[]\n\n /**\n * @property {number} [originalIndex] - Original index in the source dataset.\n * @description 元のデータセットにおけるインデックス。\n */\n originalIndex?: number\n\n /**\n * @property {Record<string, unknown>} [metadata] - Additional metadata for the result.\n * @description 結果に関連する追加のメタデータ。\n */\n metadata?: Record<string, unknown>\n}\n\n/**\n * @interface SearchResults\n * @description Represents the complete search results, including items and metadata.\n * @description アイテムとメタデータを含む完全な検索結果を表します。\n * @template T - The type of the items in the results.\n */\nexport interface SearchResults<T = unknown> {\n /**\n * @property {SearchResultItem<T>[]} results - Array of search result items.\n * @description 検索結果アイテムの配列。\n */\n results: SearchResultItem<T>[]\n\n /**\n * @property {number} totalItems - Total number of items searched.\n * @description 検索対象となった総アイテム数。\n */\n totalItems: number\n\n /**\n * @property {number} processingTime - Time taken for the search operation (ms).\n * @description 検索処理全体にかかった時間(ミリ秒)。\n */\n processingTime: number\n\n /**\n * @property {string} query - The search query that was used.\n * @description この検索で使用された検索クエリ。\n */\n query: string\n\n /**\n * @property {Partial<FuzzySearchOptions>} [options] - Search options used for this search.\n * @description この検索で使用された検索オプション。\n */\n options?: Partial<FuzzySearchOptions>\n\n /**\n * @property {SearchStats} [stats] - Additional search statistics.\n * @description 追加の検索統計情報。\n */\n stats?: SearchStats\n}\n\n// ===== Index and Strategy Types =====\n\n/**\n * @type IndexStrategy\n * @description Enumeration of available index strategies.\n * @description 利用可能なインデックス戦略の列挙。\n * - `fast`: N-gram index only for quick filtering. 高速なフィルタリングのためのN-gramインデックスのみ。\n * - `accurate`: Word-based and phonetic indexes for higher accuracy. 高精度な単語ベースおよび音韻インデックス。\n * - `hybrid`: A combination of fast and accurate strategies. 高速戦略と高精度戦略の組み合わせ。\n */\nexport type IndexStrategy = \"fast\" | \"accurate\" | \"hybrid\"\n\n/**\n * @interface IndexMetadata\n * @description Interface for metadata about the search index.\n * @description 検索インデックスに関するメタデータのインターフェース。\n */\nexport interface IndexMetadata {\n /**\n * @property {number} itemCount - Number of items indexed.\n * @description インデックス化されたアイテムの総数。\n */\n itemCount: number\n\n /**\n * @property {number} buildTime - Time taken to build the index (ms).\n * @description インデックスの構築にかかった時間(ミリ秒)。\n */\n buildTime: number\n\n /**\n * @property {number} createdAt - Index creation timestamp.\n * @description インデックスが作成されたときのタイムスタンプ。\n */\n createdAt: number\n\n /**\n * @property {string[]} indexedFields - Fields that were indexed.\n * @description インデックス化の対象となったフィールドのリスト。\n */\n indexedFields: string[]\n\n /**\n * @property {number} ngramSize - N-gram size used for indexing.\n * @description インデックス化に使用された N-gram のサイズ。\n */\n ngramSize: number\n\n /**\n * @property {IndexStrategy} [strategy] - Strategy used for indexing.\n * @description インデックス化に使用された戦略。\n */\n strategy?: IndexStrategy\n\n /**\n * @property {number} [totalIndexSize] - Total size of the index.\n * @description インデックス全体の合計サイズ。\n */\n totalIndexSize?: number\n\n /**\n * @property {object} [indexSizes] - Individual index sizes.\n * @description 各インデックスタイプ(ngram, word, phonetic)の個別サイズ。\n */\n indexSizes?: {\n ngram: number\n word: number\n phonetic: number\n }\n}\n\n// ===== Parallel Search Types =====\n\n/**\n * @type ParallelSearchStrategy\n * @description Options for parallel search strategy.\n * @description 並列検索戦略のオプション。\n *\n * @x-type-gen-skip-doc\n */\nexport type ParallelSearchStrategy = \"index-first\" | \"levenshtein-first\" | \"balanced\"\n\n/**\n * @interface ParallelSearchStageResult\n * @description Represents the result from a single stage in the parallel search pipeline.\n * @description 並列検索パイプラインの単一ステージからの結果を表します。\n * @template T - The type of the items in the results.\n */\nexport interface ParallelSearchStageResult<T = unknown> {\n /**\n * @property {'index' | 'levenshtein'} stage - Stage identifier.\n * @description ステージの識別子 ('index' または 'levenshtein')。\n */\n stage: \"index\" | \"levenshtein\"\n\n /**\n * @property {SearchResultItem<T>[]} results - Search results from this stage.\n * @description このステージからの検索結果。\n */\n results: SearchResultItem<T>[]\n\n /**\n * @property {number} processingTime - Processing time for this stage.\n * @description このステージの処理時間。\n */\n processingTime: number\n\n /**\n * @property {number} confidence - Confidence score for the results of this stage.\n * @description このステージの結果に対する信頼度スコア。\n */\n confidence: number\n\n /**\n * @property {number} candidatesProcessed - Number of candidates processed in this stage.\n * @description このステージで処理された候補数。\n */\n candidatesProcessed: number\n}\n\n/**\n * @interface MergedParallelSearchResult\n * @description Represents the merged result from the parallel search pipeline.\n * @description 並列検索パイプラインからマージされた結果を表します。\n * @template T - The type of the items in the results.\n */\nexport interface MergedParallelSearchResult<T = unknown> {\n /**\n * @property {SearchResultItem<T>[]} results - Final merged search results.\n * @description 最終的にマージされた検索結果。\n */\n results: SearchResultItem<T>[]\n\n /**\n * @property {ParallelSearchStageResult<T>} indexStage - Results from the index stage.\n * @description インデックスステージからの結果。\n */\n indexStage: ParallelSearchStageResult<T>\n\n /**\n * @property {ParallelSearchStageResult<T>} levenshteinStage - Results from the Levenshtein stage.\n * @description レーベンシュタインステージからの結果。\n */\n levenshteinStage: ParallelSearchStageResult<T>\n\n /**\n * @property {number} totalProcessingTime - Total processing time for the entire pipeline.\n * @description パイプライン全体の総処理時間。\n */\n totalProcessingTime: number\n\n /**\n * @property {ParallelSearchStrategy} mergeStrategy - Merge strategy used.\n * @description 使用されたマージ戦略。\n */\n mergeStrategy: ParallelSearchStrategy\n\n /**\n * @property {number} mergeQuality - Quality score of the merged results.\n * @description マージされた結果の品質スコア。\n */\n mergeQuality: number\n}\n\n// ===== Worker Communication Types =====\n\n/**\n * @interface IndexWorkerRequest\n * @description Defines the request structure for communication with the Indexing Worker.\n * @description インデックス作成 Worker との通信のためのリクエスト構造を定義します。\n * @template T - The type of items to be indexed or searched.\n */\nexport interface IndexWorkerRequest<T = unknown> {\n type: \"ping\" | \"buildIndex\" | \"indexSearch\" | \"getStats\" | \"resetStats\"\n id: string\n query?: string\n items?: T[]\n searchFields?: string[]\n options?: Partial<FuzzySearchOptions>\n}\n\n/**\n * @interface UnifiedWorkerResponse\n * @description Completely unified response structure for all worker types.\n * @description すべてのワーカータイプに対応する完全統一レスポンス構造。\n * @template T - The type of items in the search results.\n */\nexport interface UnifiedWorkerResponse<T = unknown> {\n type: string\n id: string\n\n // 必須フィールド\n stats: UnifiedWorkerStats\n metrics: WorkerPerformanceMetrics\n processingTime: number\n\n // 条件付きフィールド\n results?: SearchResultItem<T>[]\n error?: string\n\n // ワーカー固有情報\n workerType: \"index\" | \"levenshtein\"\n operationMeta?: Record<string, unknown>\n}\n\n/**\n * @interface LevenshteinWorkerRequest\n * @description Defines the request structure for communication with the Levenshtein Distance Worker.\n * @description Levenshtein 距離計算 Worker との通信のためのリクエスト構造を定義します。\n * @template T - The type of items to be processed.\n */\nexport interface LevenshteinWorkerRequest<T = unknown> {\n type: \"ping\" | \"setData\" | \"calculateSimilarity\" | \"batchSimilarity\" | \"getStats\" | \"levenshteinSearch\" | \"resetStats\"\n id: string\n query?: string\n items?: T[]\n searchFields?: string[]\n candidateIndices?: number[]\n targets?: string[]\n target?: string\n options?: Partial<FuzzySearchOptions>\n threshold?: number\n enablePhonetic?: boolean\n}\n\n// ===== Worker-Specific Types =====\n\n/**\n * @interface WorkerSearchStatistics\n * @description Enhanced search statistics provided by a Worker.\n * @description Worker から提供される拡張検索統計。\n */\nexport interface WorkerSearchStatistics {\n candidatesFound: number\n indexSize: number\n ngrams: number\n searchStrategy: string\n}\n\n/**\n * @interface DetailedWorkerStats\n * @description Detailed performance metrics and statistics from a Worker.\n * @description Worker からの詳細なパフォーマンス指標と統計。\n */\nexport interface DetailedWorkerStats {\n type: \"stats\"\n requestId: string\n workerStats: {\n totalSearches: number\n totalIndexBuilds: number\n currentDataSize: number\n lastIndexTime: number\n }\n memory: {\n estimatedMemoryUsage: number\n heapUsage?: number\n maxMemoryUsage?: number\n }\n performanceMetrics: {\n timings: {\n averageSearchTime: number\n averageIndexTime: number\n maxSearchTime: number\n minSearchTime: number\n }\n throughput: {\n searchesPerSecond: number\n indexOperationsPerSecond: number\n }\n }\n indexMetadata?: {\n totalTokens: number\n uniqueTokens: number\n buildTime: number\n size: number\n }\n timestamp: number\n}\n\n/**\n * @interface QueryLengthStat\n * @description Statistics related to query length.\n * @description クエリ長に関連する統計。\n */\nexport interface QueryLengthStat {\n count: number\n avgTime: number\n totalTime: number\n}\n\n/**\n * @interface FieldMatchStat\n * @description Statistics related to matches in specific fields.\n * @description 特定のフィールドでのマッチに関する統計。\n */\nexport interface FieldMatchStat {\n matches: number\n avgScore: number\n totalScore: number\n}\n\n/**\n * @interface SimilarityThresholdStats\n * @description Statistics on the distribution of similarity scores.\n * @description 類似度スコアの分布に関する統計。\n */\nexport interface SimilarityThresholdStats {\n above80: number\n above60: number\n above40: number\n below40: number\n}\n\n/**\n * @interface PerformanceInsights\n * @description Data providing insights into search performance.\n * @description 検索パフォーマンスに関する洞察を提供するデータ。\n */\nexport interface PerformanceInsights {\n recentAverageProcessingTime: number\n recentAverageResultCount: number\n throughputPerSecond: number\n totalHistoryEntries: number\n mostCommonQueryLength: number\n bestPerformingField: string\n similarityDistribution: {\n highSimilarity: number\n mediumSimilarity: number\n lowSimilarity: number\n veryLowSimilarity: number\n }\n}\n\n/**\n * @interface PerformanceHistoryEntry\n * @description Individual performance history entry for tracking operation performance.\n * @description 操作パフォーマンスを追跡するための個別のパフォーマンス履歴エントリ。\n */\nexport interface PerformanceHistoryEntry {\n timestamp: number\n queryLength: number\n itemCount: number\n processingTime: number\n resultCount: number\n operationType: string\n additionalMetrics?: Record<string, unknown>\n}\n\n/**\n * @interface FieldStatistic\n * @description Statistics for individual search fields across all operations.\n * @description 全操作における個別検索フィールドの統計。\n */\nexport interface FieldStatistic {\n matchCount: number\n averageScore: number\n totalScore: number\n bestScore: number\n worstScore: number\n}\n\n/**\n * @interface UnifiedWorkerStats\n * @description Completely unified statistics interface for all worker types.\n * @description すべてのワーカータイプに対応する完全統一統計インターフェース。\n */\nexport interface UnifiedWorkerStats {\n /**\n * @property basic Basic statistics common to all workers.\n * @description 全ワーカー共通の基本統計。\n */\n basic: {\n totalSearches: number\n totalProcessingTime: number\n averageSearchTime: number\n lastSearchTime: number\n errorCount: number\n timestamp: number\n }\n\n /**\n * @property workerSpecific Worker-type specific statistics.\n * @description ワーカータイプ固有の統計。\n */\n workerSpecific: {\n workerType: \"index\" | \"levenshtein\"\n operationCount: number\n operationDistribution: Record<string, number>\n specificMetrics: Record<string, unknown>\n }\n\n /**\n * @property analysis Advanced analysis and insights.\n * @description 高度な分析とインサイト。\n */\n analysis: {\n fieldPerformance: Record<string, FieldStatistic>\n performanceInsights: PerformanceInsights\n recentHistory: PerformanceHistoryEntry[]\n }\n}\n\n/**\n * @type WorkerStats\n * @description Unified alias for basic worker statistics.\n * @description 基本ワーカー統計の統一エイリアス。\n */\nexport type WorkerStats = UnifiedWorkerStats[\"basic\"]\n\n/**\n * @type WorkerSpecificStats\n * @description Alias for worker-specific statistics section.\n * @description ワーカー固有統計セクションのエイリアス。\n */\nexport type WorkerSpecificStats = UnifiedWorkerStats[\"workerSpecific\"]\n\n/**\n * @type WorkerAnalysis\n * @description Alias for worker analysis section.\n * @description ワーカー分析セクションのエイリアス。\n */\nexport type WorkerAnalysis = UnifiedWorkerStats[\"analysis\"]\n\n/**\n * @interface WorkerPerformanceMetrics\n * @description Performance metrics for detailed monitoring of a Worker.\n * @description Worker の詳細な監視のためのパフォーマンスメトリクス。\n */\nexport interface WorkerPerformanceMetrics {\n timings: {\n averageProcessingTime: number\n fastestProcessing: number\n slowestProcessing: number\n lastProcessingTime: number\n }\n throughput: {\n operationsPerSecond: number\n totalOperations: number\n }\n quality: {\n successRate: number\n errorRate: number\n timeoutRate: number\n }\n}\n\n// ===== Search Statistics Types =====\n\n/**\n * @interface SearchStats\n * @description Overall search statistics for performance monitoring.\n * @description パフォーマンス監視のための全体的な検索統計。\n */\nexport interface SearchStats {\n /**\n * @property {number} totalSearches - Total number of searches performed.\n * @description 実行された総検索数。\n */\n totalSearches: number\n\n /**\n * @property {number} averageSearchTime - Average search time in milliseconds.\n * @description 平均検索時間(ミリ秒)。\n */\n averageSearchTime: number\n\n /**\n * @property {Array<{ query: string; count: number }>} popularQueries - Popular search queries.\n * @description 人気のある検索クエリとその実行回数。\n */\n popularQueries: Array<{ query: string; count: number }>\n\n /**\n * @property {Record<string, { averageTime: number; sampleSize: number }>} performanceBySize - Performance statistics by dataset size.\n * @description データセットのサイズ別のパフォーマンス統計。\n */\n performanceBySize: Record<string, { averageTime: number; sampleSize: number }>\n\n /**\n * @property {object} workers - Worker statistics information.\n * @description 各ワーカーの統計情報。\n */\n workers: {\n index: {\n stats: UnifiedWorkerStats\n }\n levenshtein: {\n stats: UnifiedWorkerStats\n }\n }\n}\n\n/**\n * @interface SearchStatistics\n * @description Search statistics provided by a worker.\n * @description Worker から提供される検索統計。\n */\nexport interface SearchStatistics {\n candidatesFound: number\n indexSize: number\n ngrams: number\n words?: number\n phonetic?: number\n searchStrategy: string\n}\n\n/**\n * @interface SearchHistory\n * @description Represents a single entry in the search history for learning and analytics.\n * @description 学習と分析のための検索履歴の単一エントリを表します。\n */\nexport interface SearchHistory {\n /**\n * @property {string} query - The search query.\n * @description 検索クエリ。\n */\n query: string\n\n /**\n * @property {number} timestamp - Timestamp of the search.\n * @description 検索が実行されたときのタイムスタンプ。\n */\n timestamp: number\n\n /**\n * @property {number} resultCount - Number of results found.\n * @description 見つかった結果の数。\n */\n resultCount: number\n\n /**\n * @property {number} processingTime - Processing time in milliseconds.\n * @description 処理にかかった時間(ミリ秒)。\n */\n processingTime: number\n\n /**\n * @property {number} [searchTime] - Alias for processingTime.\n * @description processingTime のエイリアス。\n */\n searchTime?: number\n\n /**\n * @property {number} [selectedIndex] - Index of the selected result, if any.\n * @description ユーザーが選択した結果のインデックス(存在する場合)。\n */\n selectedIndex?: number\n\n /**\n * @property {string} [selectedItemId] - ID of the selected item, if any.\n * @description ユーザーが選択したアイテムのID(存在する場合)。\n */\n selectedItemId?: string\n\n /**\n * @property {number} [satisfactionScore] - User satisfaction score (1-5).\n * @description ユーザー満足度スコア(1-5)。\n */\n satisfactionScore?: number\n\n /**\n * @property {boolean} successful - Whether the search was considered successful.\n * @description 検索が成功したと見なされたかどうか。\n */\n successful: boolean\n\n /**\n * @property {string} [context] - Context or source of the search.\n * @description 検索が実行されたコンテキストまたはソース。\n */\n context?: string\n}\n\n/**\n * @interface LearningData\n * @description Data structure for storing learned information to improve search results.\n * @description 検索結果を改善するために学習した情報を格納するためのデータ構造。\n */\nexport interface LearningData {\n /**\n * @property {Record<string, number>} fieldWeights - Field-specific weights learned from user behavior.\n * @description ユーザーの行動から学習したフィールド固有の重み。\n */\n fieldWeights: Record<string, number>\n\n /**\n * @property {Record<string, number>} queryPatterns - Query patterns and their frequency count.\n * @description クエリのパターンとその出現頻度。\n */\n queryPatterns: Record<string, number>\n\n /**\n * @property {object} userPreferences - User preferences and behavior.\n * @description ユーザーの好みと行動の記録。\n */\n userPreferences: {\n preferredThreshold: number\n frequentFields: string[]\n searchStyle: \"exact\" | \"fuzzy\" | \"mixed\"\n lastUsedOptions: Partial<FuzzySearchOptions>\n }\n\n /**\n * @property {object} performanceMetrics - Performance metrics for learning optimization.\n * @description 学習の最適化に使用されるパフォーマンス指標。\n */\n performanceMetrics: {\n averageSearchTime: Record<string, number>\n indexBuildTime: number\n }\n}\n\n// ===== Utility Types =====\n\n/**\n * @type ExtractItemType\n * @description Utility type to extract the item type from a SearchResultItem.\n * @description SearchResultItem からアイテムの型を抽出するためのユーティリティ型。\n * @template T - The type of the SearchResultItem.\n */\nexport type ExtractItemType<T> = T extends SearchResultItem<infer U> ? U : never\n\n/**\n * @type SearchFields\n * @description Defines the search fields with type safety, accepting keys of T or strings.\n * @description 型安全性を備えた検索フィールドを定義します。T のキーまたは文字列を受け入れます。\n * @template T - The type of the items being searched.\n */\nexport type SearchFields<T> = Array<keyof T | string>\n\n/**\n * @type SearchResultCallback\n * @description Callback function type for handling search results.\n * @description 検索結果を処理するためのコールバック関数型。\n * @template T - The type of the items in the results.\n */\nexport type SearchResultCallback<T> = (results: SearchResults<T>) => void\n\n// ===== Type Guards =====\n\n/**\n * @function isSearchResultItem\n * @description Type guard to check if an object is a SearchResultItem.\n * @description オブジェクトが SearchResultItem かどうかをチェックする型ガード。\n * @param {unknown} obj - The object to check.\n * @returns {boolean} - True if the object is a SearchResultItem.\n * @template T - The expected type of the item within the SearchResultItem.\n */\nexport function isSearchResultItem<T>(obj: unknown): obj is SearchResultItem<T> {\n // オブジェクトであり、null でなく、必須プロパティが存在するかをチェック\n return typeof obj === \"object\" && obj !== null && \"item\" in obj && \"score\" in obj && \"matchedFields\" in obj\n}\n\n// ===== React Hook Types =====\n\n/**\n * @type UseFuzzySearchOptions\n * @description Options type for the useFuzzySearch hook, extending PartialFuzzySearchOptions.\n * @description useFuzzySearch フック用のオプション型。PartialFuzzySearchOptions を拡張します。\n */\nexport type UseFuzzySearchOptions = PartialFuzzySearchOptions\n\n/**\n * @interface SearchHistoryResult\n * @description The return type for a hook that manages search history.\n * @description 検索履歴を管理するフックの戻り値の型。\n */\nexport interface SearchHistoryResult {\n searchHistory: SearchHistory[]\n addToHistory: (term: string) => void\n clearHistory: () => void\n}\n\n/**\n * @interface PerformanceMetrics\n * @description Data type for the performance metrics callback.\n * @description パフォーマンス指標コールバック用のデータ型。\n */\nexport interface PerformanceMetrics {\n totalSearches: number\n averageSearchTime: number\n itemCount: number\n resultsCount: number\n workerStats?: {\n index?: UnifiedWorkerStats\n levenshtein?: UnifiedWorkerStats\n }\n}\n\n/**\n * @interface FuzzySearchResult\n * @description The return type for the simplified fuzzy search hook.\n * @description 簡易版のあいまい検索フックの戻り値の型。\n * @template T - The type of the items being searched.\n */\nexport interface FuzzySearchResult<T> {\n searchTerm: string\n setSearchTerm: (term: string) => void\n filteredItems: SearchResultItem<T>[]\n isSearching: boolean\n isIndexBuilding: boolean\n error: string | null\n searchHistory: SearchHistory[]\n options: FuzzySearchOptions\n selectItem: (item: T, index: number) => void\n clearSearch: () => void\n clearHistory: () => void\n resetStats: () => Promise<void>\n getSearchSuggestions: (query: string, limit?: number) => string[]\n performanceMetrics: PerformanceMetrics\n rebuildIndex: (customOptions?: UseFuzzySearchOptions) => Promise<void>\n}\n","/**\n * Common types and utilities for fuzzy search workers.\n * あいまい検索ワーカー用の共通型とユーティリティ。\n */\n\nimport type { FieldStatistic, PerformanceHistoryEntry, PerformanceInsights, UnifiedWorkerStats, WorkerPerformanceMetrics, WorkerStats } from \"../types/index\"\n\nconst LOG_PREFIX = \"[fuzzy-search]\"\n\n/**\n * Provides a base class for workers with common functionality for statistics and performance metrics.\n * This class is intended to be extended by specific worker implementations.\n * 統計およびパフォーマンスメトリクスの共通機能を備えたワーカーの基本クラスを提供します。\n * このクラスは、特定のワーカー実装によって拡張されることを意図しています。\n */\nexport abstract class BaseWorker {\n /**\n * Stores basic statistics about the worker's operations.\n * ワーカーの操作に関する基本的な統計を保存します。\n */\n protected stats: WorkerStats = {\n totalSearches: 0,\n totalProcessingTime: 0,\n averageSearchTime: 0,\n lastSearchTime: 0,\n errorCount: 0,\n timestamp: Date.now(),\n }\n\n /**\n * Unified detailed statistics for all worker types.\n * 全ワーカータイプの統一詳細統計。\n */\n protected detailedStats: Map<string, unknown> = new Map()\n protected performanceHistory: PerformanceHistoryEntry[] = []\n protected operationDistribution: Map<string, number> = new Map()\n protected fieldStats: Map<string, FieldStatistic> = new Map()\n\n /**\n * Stores detailed performance metrics of the worker.\n * ワーカーの詳細なパフォーマンスメトリクスを保存します。\n */\n protected metrics: WorkerPerformanceMetrics = {\n timings: {\n averageProcessingTime: 0,\n fastestProcessing: Infinity,\n slowestProcessing: 0,\n lastProcessingTime: 0,\n },\n throughput: {\n operationsPerSecond: 0,\n totalOperations: 0,\n },\n quality: {\n successRate: 1,\n errorRate: 0,\n timeoutRate: 0,\n },\n }\n\n /**\n * Updates the statistics and performance metrics after an operation.\n * @param processingTime The time taken for the operation in milliseconds.\n * @param success A boolean indicating if the operation was successful.\n * 操作後に統計およびパフォーマンスメトリクスを更新します。\n * @param processingTime 操作にかかった時間(ミリ秒)。\n * @param success 操作が成功したかどうかを示すブール値。\n */\n protected updateStats(processingTime: number, success: boolean = true): void {\n // 基本的な統計を更新します\n this.stats.totalSearches++\n this.stats.totalProcessingTime += processingTime\n this.stats.averageSearchTime = this.stats.totalProcessingTime / this.stats.totalSearches\n this.stats.lastSearchTime = processingTime\n\n // タイミングメトリクスを更新します\n this.metrics.timings.lastProcessingTime = processingTime\n this.metrics.timings.averageProcessingTime = this.stats.averageSearchTime\n this.metrics.timings.fastestProcessing = Math.min(this.metrics.timings.fastestProcessing, processingTime)\n this.metrics.timings.slowestProcessing = Math.max(this.metrics.timings.slowestProcessing, processingTime)\n\n // スループットメトリクスを更新します\n this.metrics.throughput.totalOperations++\n if (this.metrics.timings.averageProcessingTime > 0) {\n this.metrics.throughput.operationsPerSecond = 1000 / this.metrics.timings.averageProcessingTime\n }\n\n // 失敗した場合、エラーカウントをインクリメントします\n if (!success) {\n this.stats.errorCount++\n }\n\n // 品質メトリクスを更新します\n const totalOps = this.metrics.throughput.totalOperations\n this.metrics.quality.successRate = (totalOps - this.stats.errorCount) / totalOps\n this.metrics.quality.errorRate = this.stats.errorCount / totalOps\n }\n\n /**\n * Gets a copy of the current worker statistics.\n * @returns An object containing the worker's statistics.\n * 現在のワーカ統計のコピーを取得します。\n * @returns ワーカーの統計を含むオブジェクト。\n */\n getStats(): WorkerStats {\n // 統計オブジェクトのコピーを返します\n return { ...this.stats }\n }\n\n /**\n * Gets a copy of the current worker performance metrics.\n * @returns An object containing the worker's performance metrics.\n * 現在のワーカーパフォーマンスメトリクスのコピーを取得します。\n * @returns ワーカーのパフォーマンスメトリクスを含むオブジェクト。\n */\n getMetrics(): WorkerPerformanceMetrics {\n // メトリクスオブジェクトのコピーを返します\n return { ...this.metrics }\n }\n\n /**\n * Resets all worker statistics and performance metrics to initial state.\n * This method can be overridden by child classes to reset worker-specific statistics.\n * 全ての統計情報とパフォーマンスメトリクスを初期状態にリセットします。\n * このメソッドは子クラスで固有統計をリセットするためにオーバーライドできます。\n */\n resetStats(): void {\n // 基本統計をリセット\n this.stats = {\n totalSearches: 0,\n totalProcessingTime: 0,\n averageSearchTime: 0,\n lastSearchTime: 0,\n errorCount: 0,\n timestamp: Date.now(),\n }\n\n // パフォーマンスメトリクスをリセット\n this.metrics = {\n timings: {\n averageProcessingTime: 0,\n fastestProcessing: Infinity,\n slowestProcessing: 0,\n lastProcessingTime: 0,\n },\n throughput: {\n operationsPerSecond: 0,\n totalOperations: 0,\n },\n quality: {\n successRate: 1,\n errorRate: 0,\n timeoutRate: 0,\n },\n }\n\n // 統一統計をリセット\n this.detailedStats.clear()\n this.performanceHistory = []\n this.operationDistribution.clear()\n this.fieldStats.clear()\n\n console.log(`${LOG_PREFIX} 📊 ${this.getWorkerType()} Worker: Statistics reset completed`)\n }\n\n /**\n * Updates unified worker statistics with operation-specific data.\n * @param operationType The type of operation performed.\n * @param processingTime The time taken for the operation.\n * @param additionalData Additional metrics specific to the operation.\n * 操作固有データで統一ワーカー統計を更新します。\n * @param operationType 実行された操作のタイプ。\n * @param processingTime 操作にかかった時間。\n * @param additionalData 操作固有の追加メトリクス。\n */\n protected updateWorkerStats(operationType: string, processingTime: number, additionalData: Record<string, unknown> = {}): void {\n // 基本統計更新\n this.updateStats(processingTime, true)\n\n // 操作統計更新\n const currentCount = this.operationDistribution.get(operationType) || 0\n this.operationDistribution.set(operationType, currentCount + 1)\n\n // 詳細データ保存\n Object.entries(additionalData).forEach(([key, value]) => {\n this.detailedStats.set(key, value)\n })\n\n // パフォーマンス履歴追加\n this.addPerformanceEntry({\n timestamp: Date.now(),\n operationType,\n processingTime,\n queryLength: (additionalData.queryLength as number) || 0,\n itemCount: (additionalData.itemCount as number) || 0,\n resultCount: (additionalData.resultCount as number) || 0,\n additionalMetrics: additionalData,\n })\n }\n\n /**\n * Updates field-specific statistics.\n * @param field The search field name.\n * @param score The match score for this field.\n * フィールド固有の統計を更新します。\n * @param field 検索フィールド名。\n * @param score このフィールドのマッチスコア。\n */\n protected updateFieldStats(field: string, score: number): void {\n const current = this.fieldStats.get(field) || {\n matchCount: 0,\n averageScore: 0,\n totalScore: 0,\n bestScore: 0,\n worstScore: 1,\n }\n\n current.matchCount += 1\n current.totalScore += score\n current.averageScore = current.totalScore / current.matchCount\n current.bestScore = Math.max(current.bestScore, score)\n current.worstScore = Math.min(current.worstScore, score)\n\n this.fieldStats.set(field, current)\n }\n\n /**\n * Adds a performance history entry with size limit.\n * @param entry The performance entry to add.\n * サイズ制限付きでパフォーマンス履歴エントリを追加します。\n * @param entry 追加するパフォーマンスエントリ。\n */\n protected addPerformanceEntry(entry: PerformanceHistoryEntry): void {\n this.performanceHistory.push(entry)\n\n // 履歴のサイズ制限(最新100件)\n if (this.performanceHistory.length > 100) {\n this.performanceHistory = this.performanceHistory.slice(-100)\n }\n }\n\n /**\n * Gets unified worker statistics including all analysis data.\n * @returns Complete unified statistics for this worker.\n * すべての分析データを含む統一ワーカー統計を取得します。\n * @returns このワーカーの完全な統一統計。\n */\n public getWorkerStats(): UnifiedWorkerStats {\n return {\n basic: {\n ...this.stats,\n timestamp: Date.now(),\n },\n workerSpecific: {\n workerType: this.getWorkerType(),\n operationCount: this.getTotalOperations(),\n operationDistribution: Object.fromEntries(this.operationDistribution),\n specificMetrics: this.getSpecificMetrics(),\n },\n analysis: {\n fieldPerformance: Object.fromEntries(this.fieldStats),\n performanceInsights: this.generatePerformanceInsights(),\n recentHistory: this.performanceHistory.slice(-10),\n },\n }\n }\n\n /**\n * Sends unified statistics update to the main thread.\n * メインスレッドに統一統計更新を送信します。\n */\n protected sendStatsUpdate(): void {\n const response = {\n type: \"stats\",\n id: `stats-${Date.now()}`,\n stats: this.getWorkerStats(),\n metrics: this.getMetrics(),\n processingTime: 0,\n workerType: this.getWorkerType(),\n operationMeta: {},\n }\n\n console.log(`${LOG_PREFIX} 📊 ${this.getWorkerType()} Worker: Sending unified stats update`)\n self.postMessage(response)\n }\n\n // 抽象メソッド - 子クラスで実装が必要\n protected abstract getWorkerType(): \"index\" | \"levenshtein\"\n protected abstract getSpecificMetrics(): Record<string, unknown>\n\n /**\n * Gets the total number of operations performed by this worker.\n * @returns The total operation count.\n * このワーカーが実行した操作の総数を取得します。\n * @returns 総操作数。\n */\n protected getTotalOperations(): number {\n return Array.from(this.operationDistribution.values()).reduce((sum, count) => sum + count, 0)\n }\n\n /**\n * Generates performance insights from historical data.\n * @returns Performance insights object.\n * 履歴データからパフォーマンスインサイトを生成します。\n * @returns パフォーマンスインサイトオブジェクト。\n */\n protected generatePerformanceInsights(): PerformanceInsights {\n if (this.performanceHistory.length === 0) {\n return {\n recentAverageProcessingTime: 0,\n recentAverageResultCount: 0,\n throughputPerSecond: 0,\n totalHistoryEntries: 0,\n mostCommonQueryLength: 0,\n bestPerformingField: \"\",\n similarityDistribution: {\n highSimilarity: 0,\n mediumSimilarity: 0,\n lowSimilarity: 0,\n veryLowSimilarity: 0,\n },\n }\n }\n\n const recent = this.performanceHistory.slice(-10)\n const avgProcessingTime = recent.reduce((sum, h) => sum + h.processingTime, 0) / recent.length\n const avgResultCount = recent.reduce((sum, h) => sum + h.resultCount, 0) / recent.length\n\n // 最も一般的なクエリ長を計算\n const queryLengths = new Map<number, number>()\n this.performanceHistory.forEach((entry) => {\n const current = queryLengths.get(entry.queryLength) || 0\n queryLengths.set(entry.queryLength, current + 1)\n })\n\n let mostCommonQueryLength = 0\n let maxCount = 0\n queryLengths.forEach((count, length) => {\n if (count > maxCount) {\n maxCount = count\n mostCommonQueryLength = length\n }\n })\n\n // 最高パフォーマンスフィールドを計算\n let bestField = \"\"\n let bestScore = 0\n this.fieldStats.forEach((stat, field) => {\n if (stat.averageScore > bestScore) {\n bestScore = stat.averageScore\n bestField = field\n }\n })\n\n return {\n recentAverageProcessingTime: avgProcessingTime,\n recentAverageResultCount: avgResultCount,\n throughputPerSecond: avgProcessingTime > 0 ? 1000 / avgProcessingTime : 0,\n totalHistoryEntries: this.performanceHistory.length,\n mostCommonQueryLength,\n bestPerformingField: bestField,\n similarityDistribution: {\n highSimilarity: 0,\n mediumSimilarity: 0,\n lowSimilarity: 0,\n veryLowSimilarity: 0,\n },\n }\n }\n\n /**\n * Placeholder for handling messages from the main thread. This should be overridden by child classes.\n * @param _event The message event.\n * メインスレッドからのメッセージを処理するためのプレースホルダー。子クラスでオーバーライドする必要があります。\n * @param _event メッセージイベント。\n */\n handleMessage(_event: MessageEvent): void {\n // デフォルト実装 - 子クラスでオーバーライドする必要があります\n console.warn(`${LOG_PREFIX} ⚠️ BaseWorker.handleMessage: No implementation provided`)\n }\n}\n","/**\n * Index Strategy Web Worker for fuzzy search.\n * あいまい検索用のインデックス戦略Web Worker。\n *\n * This worker specializes in building and managing search indices,\n * candidate filtering, and index-based optimizations.\n * このワーカーは検索インデックスの構築・管理、候補フィルタリング、\n * インデックスベースの最適化に特化しています。\n */\n\nimport type { FuzzySearchOptions, IndexMetadata, IndexWorkerRequest, PerformanceInsights, SearchResultItem, SimilarityThresholdStats, UnifiedWorkerResponse } from \"../types/index\"\nimport { DEFAULT_FUZZY_SEARCH_OPTIONS } from \"../types/index\"\nimport { BaseWorker } from \"./common\"\n\nconst LOG_PREFIX = \"[fuzzy-search]\"\n\n/**\n * Implements the index strategy worker.\n * インデックス戦略ワーカーを実装します。\n */\nclass IndexStrategyWorker extends BaseWorker {\n // 複合インデックスキャッシュ\n private ngramCache = new Map<string, Set<number>>()\n private wordCache = new Map<string, Set<number>>()\n private phoneticCache = new Map<string, Set<number>>()\n\n // データキャッシュ\n private currentItems: unknown[] = []\n private currentSearchFields: string[] = []\n private indexMetadata: IndexMetadata | null = null\n\n // Index Worker 専用統計\n private indexStats = {\n totalIndexBuilds: 0,\n currentDataSize: 0,\n lastIndexTime: 0,\n }\n\n // 類似度分布統計\n private similarityThresholdStats: SimilarityThresholdStats = {\n above80: 0,\n above60: 0,\n above40: 0,\n below40: 0,\n }\n\n /**\n * Gets the worker type for unified statistics.\n * @returns The worker type identifier.\n * 統一統計用のワーカータイプを取得します。\n * @returns ワーカータイプ識別子。\n */\n protected getWorkerType(): \"index\" {\n return \"index\"\n }\n\n /**\n * Gets worker-specific metrics for unified statistics.\n * @returns Worker-specific metrics object.\n * 統一統計用のワーカー固有メトリクスを取得します。\n * @returns ワーカー固有メトリクスオブジェクト。\n */\n protected getSpecificMetrics(): Record<string, unknown> {\n return {\n totalIndexBuilds: this.indexStats.totalIndexBuilds,\n currentDataSize: this.indexStats.currentDataSize,\n lastIndexTime: this.indexStats.lastIndexTime,\n cacheSize: {\n ngram: this.ngramCache.size,\n word: this.wordCache.size,\n phonetic: this.phoneticCache.size,\n },\n indexMetadata: this.indexMetadata || {},\n similarityThresholds: { ...this.similarityThresholdStats },\n }\n }\n\n /**\n * Resets only Index Worker specific statistics to initial state.\n * Index Worker 固有の統計情報のみを初期状態にリセットします。\n */\n resetStats(): void {\n // 基底クラスの統計リセット\n super.resetStats()\n\n // Index Worker 固有の統計をリセット\n this.indexStats = {\n totalIndexBuilds: 0,\n currentDataSize: 0,\n lastIndexTime: 0,\n }\n\n // 類似度統計をリセット\n this.similarityThresholdStats = {\n above80: 0,\n above60: 0,\n above40: 0,\n below40: 0,\n }\n\n console.log(`${LOG_PREFIX} 🔧 Index Worker: All statistics reset completed`)\n }\n\n /**\n * Updates similarity threshold statistics based on the score.\n * @param score The similarity score (0-1).\n * スコアに基づいて類似度しきい値統計を更新します。\n * @param score 類似度スコア (0-1)。\n */\n private updateSimilarityStats(score: number): void {\n if (score >= 0.8) {\n this.similarityThresholdStats.above80++\n } else if (score >= 0.6) {\n this.similarityThresholdStats.above60++\n } else if (score >= 0.4) {\n this.similarityThresholdStats.above40++\n } else {\n this.simila