互換性
フェイクで通ったテストが何かを証明するのは、テストが見ている箇所で、フェイクが本物と同じように振る舞う場合だけです。このページは、osmemについてそれを判断するための一覧です。実装しているもの、近似しているもの、意図的にエラーにするもの。
明示的に未対応とした機能の多くは400 unsupported_operation_exceptionを返します。応答の形、ステータスコード、エラーの種類とメッセージはOpenSearchに合わせています(OpenSearch 3.8.0を基準に、2.19.1でも確認)。一方、近似した動作をする機能や、受理して無視する検索オプションもあります。そうした差は以下に記載します。回帰テストは個々の挙動を確認するもので、OpenSearchの全機能との同等性を保証するものではありません。
実装しているもの
Section titled “実装しているもの”インデックス。 設定・マッピング・エイリアス付きの作成、ワイルドカードと_allでの削除、存在確認、取得、_mappingの取得と更新、OpenSearchの設定レジストリで検証する_settingsの取得と更新(未知・不正・private・static・finalの設定はOpenSearchと同じメッセージで拒否し、include_defaults、flat_settings、settings_filterに対応)、全セクションとlevel=shardsに対応した_stats、_resolve/index、何もしない_refresh・_flush・_forcemerge、実際にclosed状態を持つ_open・_close(closed indexへの検索・取得・書き込みはindex_closed_exceptionになり、wildcardはexpand_wildcardsで指定しない限りclosed indexを含めず、_cat/indicesとcluster healthではcloseとredを表示し、analysis設定の変更は再open時に反映)、読み取り・書き込み・メタデータ変更に対するindexブロックとclusterブロック(index.blocks.*、cluster.blocks.*)、level・wait_for_*パラメータと408のタイムアウト応答に対応したcluster health、クラスタのsettings・state・stats、スニッフィングするクライアント向けに実際のアドレスを返す_nodes。composable・component・legacyのインデックステンプレートは合成したうえで、自動作成を含むインデックス作成時に適用し、simulationは重複するテンプレートも報告します。hidden indexとhidden aliasは、-nameによる除外を含め、OpenSearchの解決規則に従ってexpand_wildcards・ignore_unavailable・allow_no_indicesを扱います。
cat API。 _cat/indices、aliases、health、count、nodes、master/cluster_manager、plugins、templates、shards、segments、recovery、allocation、thread_pool、pending_tasks、fielddata、nodeattrs、tasks、repositories、snapshots、segment_replication。format、h(別名とワイルドカードを含む)、v、s、help、bytes、time、priに対応し、列の配置もOpenSearchに合わせています。
ドキュメント。 自動id、検証済みのop_type、index・update・deleteでのif_seq_no/if_primary_term、internal・external・external_gt・external_gteのversionに対応した_doc。DELETEはexternal versionを検査し、削除した文書はindex.gc_deletes(既定60秒)の間tombstoneを残すので、削除後もversionが連続します。_create、doc・doc_as_upsert・upsert(存在しないindexを作成)・detect_noopに対応した_update、_source、文書ごとの失敗を返す_mget、OpenSearchと同じく行単位で解析し、require_alias・空のid・必須routingをアイテムごとのエラーにする_bulk、_delete_by_queryと_update_by_query(queryが必須、conflicts・max_docs・slices・wait_for_completion=falseのtaskに対応)、source/destの検証、max_docs、external宛先versionに対応した_reindex。GETと検索結果のhitは_routingと_ignoredを返します。_countのボディはqueryだけを受け付けます。write indexのない複数index向けaliasへの書き込みは、OpenSearchと同じく失敗します。
マッピング。 text(analyzer、search_analyzer、マルチフィールド)、match_only_text、keyword(normalizer、ignore_above、0を含む)、OpenSearchと同じ値の検証と型変換を行うすべての数値型、boolean、名前付きフォーマット・Javaパターン・epochフォーマットに対応したdateとdate_nanos(1677〜2262年の範囲外の日付とナノ秒精度を含む)、入力形式に対応したgeo_point、ip、objectとnested、フィールドエイリアス、null_value、copy_to、index: false(OpenSearchと同じくクエリはdoc valuesを使用)、enabled: false、ignore_malformed(そのフィールドだけを読み飛ばし_ignoredに記録)、coerce、dynamic: true/false/strict/strict_allow_templates/false_allow_templates、dynamic template(match、path_match、match_mapping_type、{name}と{dynamic_type})、range型(integer_range、long_range、float_range、double_range、date_range、ip_range)、._2gram…と._index_prefixサブフィールドを持つsearch_as_you_type、flat_object、join、rank_feature、rank_features、knn_vector(値は検証しますが、kNN検索は未実装)と、contexts(categoryとgeo)に対応したcompletion、nestedフィールドのinclude_in_parentとinclude_in_root、similarity: boolean。マッピングのパラメータはフィールド型ごとに検証します。未知・不正なパラメータはOpenSearchと同じ「Failed to parse mapping」のエラーになり、変更できないパラメータを変える更新は「Cannot update parameter [x] from [a] to [b]」で失敗します。total_fields.limit、depth.limit、nested_fields.limit、field_name_length.limit、文書単位のnested_objects.limit、index単位のindex.mapping.ignore_malformedを適用します。動的マッピングはOpenSearchに従います。文字列は.keywordサブフィールド付きのtextになり、日付と数値はdate_detectionとnumeric_detectionに従って検出し、ドットを含むキーはオブジェクトに展開します。derivedフィールドとstar-treeのcompositeマッピングは未対応として拒否します。
クエリ。 クエリは実行前に全体を解析し、不正なクエリはOpenSearchと同じエラーの種類とメッセージで失敗します。match(operator、minimum_should_match、transpositionsを含むfuzziness、zero_terms_query)、実際のトークン位置を使うmatch_phraseとmatch_phrase_prefix(ストップワードの空き、position_increment_gap、max_expansions)、match_bool_prefix、multi_match(全type、フィールドパターン、ブースト、lenient、analyzerごとにフィールドをまとめるcross_fields)、combined_fields、common、マッピングの型に従うtermとterms(terms lookup、case_insensitive)、terms_set、数値と日付に対するrange(日付演算、format、time_zone)、exists、prefix、wildcard、regexp(Luceneの構文とflags)、fuzzy(max_expansions、transpositions)、ids、bool、constant_score、dis_max(tie_breaker)、boosting(negativeとnegative_boost)、function_score(weight、field_value_factor、random_score、decay関数、全score mode・boost mode、max_boost、min_score)、nested(score_mode、ignore_unmapped、inner_hits)、query_string(正規表現・エスケープ・構文エラーを含むLuceneのclassic構文)とsimple_query_string(flags)、geo_distance、geo_bounding_box、geo_polygon(geohashとWKTのBBOX入力、全距離単位)、range型フィールドへのrange(relation)、rank_feature(saturation、log、sigmoid、linear)、parent_id、has_childとhas_parent(inner_hitsなし)、flat_objectのサブフィールドへのterm、wrapper、intervals(match・prefix・wildcard・fuzzy・regexp・all_of・any_ofとfilterを、存在の近似ではなく実際の位置情報によるマッチングとして実装)、span_term・span_near・span_multi、more_like_this、distance_feature(date・date_nanos・geo_pointのpivot)、geo_pointフィールドに対するgeo_shape(envelope・polygon・circle形状のintersects関係)。term系クエリのスコアはOpenSearchと同じく定数(1×boost)で、名前付きクエリはhitにmatched_queriesを付け、index.query.default_fieldを適用します。
検索。 index.max_result_window(既定は10,000件、index単位で変更可)までのfrom/size、フィールドによるソート(order、missing、mode、unmapped_type。formatキーはOpenSearchと同じく拒否)、_score・_doc・_idでのソート、欠損した数値や日付にOpenSearchと同じ番兵値を使うsearch_after、scroll、作成時点のindexを保持するpoint in time、_sourceのフィルタリング、fields、docvalue_fields、version、seq_no_primary_term、track_total_hits、track_scores、min_score、post_filter、inner_hits付きのcollapse、rescore(window_size、重み、すべてのscore mode)、indices_boost、scrollとpoint in timeのslice、_count、_msearch、typed_keys、preference=_shards:、phase_took、_geo_distanceによるソート、_field_caps(メタデータフィールド、index_filter、meta、検索・集計できないindexの一覧を含む)、explain・rewrite・all_shardsに対応した/{index}/_validate/query、/{index}/_explain/{id}とhitのexplain(いずれもfilter付きaliasのfilterを反映)、設定したshard・replica数をもとにした_search_shards(routing、preference、リクエストボディのsliceに対応)、既にindexされた文書に対する/{index}/_termvectors/{id}と_mtermvectors(field_statistics、term_statistics、positions、offsets、realtime)、除外指定と**を含むfilter_path、pretty、rest_total_hits_as_int、URLパラメータsource、gzipで圧縮されたリクエストボディ。ハイライトはOpenSearchのunified・plain・fvhの3種類を実装しています。文と単語の境界スキャナ、fragment_size、number_of_fragments、order: score、no_match_size、require_field_match、highlight_query、matched_fields、tags_schema、html encoder、max_analyzer_offsetに対応し、nestedとcollapseのinner hitsもハイライトします。totalはsearch_afterによるページングやcollapseの前に一致した文書数を返します。terminate_afterはindex順にshardごとに件数を数え、集計付きのsize 0検索ではOpenSearch 3.8と同じくterminated_earlyを返します。検索ボディのキーは文書中の順にOpenSearchと同じメッセージで検証し、スコア関数はスコアが必要な場合だけ実行します。
Painlessスクリプト。 依存関係のない読み取り専用のPainlessサブセット(painlessscript-go)で、script_fields、scriptおよびscript_scoreクエリ、function_scoreのscript_score関数、_scriptによるソート、bucket_script/bucket_selectorパイプライン集計を実行します。文書スクリプトはdoc['field'].value/.size()、params、_scoreを読み取れます。bucket_script/bucket_selectorのスクリプトはparamsのみを読み取り(スクリプト自身の静的paramsとbuckets_pathの値をマージしたもの)、doc[...]は使えません。どちらもスクリプトからMath、DateTime/Instant、Java形式のStringメソッド、スクリプト内で宣言したローカルなlist・mapを利用できます。コンパイルに失敗した、または実行時に例外を投げたスクリプトは、OpenSearchと同じくscript_exceptionを返します。
集計。 集計リクエストは実行前に解析・検証し、OpenSearchと同じエラーを返します。バケット集計: terms(size、並べ替え、min_doc_count、missing、Luceneの正規表現によるinclude/exclude、show_term_doc_count_error)、multi_terms、rare_terms、significant_termsとsignificant_text(jlh・chi_square・gnd・mutual_information・percentageの各heuristic)、range、date_range、ip_range、geo_distance、histogram、date_histogram(calendarとfixedの間隔、夏時間を正しく丸めるtime_zone、offset、format、extended_bounds、空バケットの補完)、auto_date_histogram、variable_width_histogram、filter、filters、adjacency_matrix、missing、global、nestedとreverse_nested、sampler、after付きのcomposite(reverse_nestedの子としても使用可)、geohash_grid、geotile_grid。数値系メトリクスとrange・compositeのbucket keyは、2^53を超えるunsigned_longもdouble同様に扱います。メトリクス集計: avg、sum、min、max、value_count、stats、extended_stats、cardinality、percentilesとpercentile_ranks(OpenSearchと同じt-digest。hdr methodは未実装)、median_absolute_deviation、top_hits、weighted_avg、geo_bounds、geo_centroid。パイプライン集計: cumulative_sum、derivative、bucket_sort、avg/sum/min/max/stats/extended_stats/percentiles_bucket、serial_diff、moving_avg(simple、linear、ewmaモデル)、bucket_scriptとbucket_selector(buckets_pathは単一のパス、または名前とパスの対応を表すオブジェクトのいずれも指定可能)。search.max_bucketsは固定値ではなくcluster設定(transient、次いでpersistent)から読み取ります。応答にはmeta、typed_keys、formatに従う*_as_stringを出力します。サブ集計は入れ子にできます。
サジェスター。 _searchボディのsuggestは、term(索引済みtermへの編集距離による補正)、phrase(stupid-backoffのn-gramモデルでスコア付けする候補生成。Luceneの平滑化モデルの近似、「近似」節を参照)、completionの3種類のsuggesterに対応します。completionフィールドはcontexts(categoryとgeo。索引時の必須context検証を含む)、skip_duplicates、weightによる順序付け、fuzzy prefixマッチに対応します。
解析。 _analyzeは、osmemが実装する組み込みのアナライザ・トークナイザ・トークンフィルタ・文字フィルタについて、OpenSearchと同じトークンtype、UTF-16のoffset、explainの出力を返します。実装していないコンポーネントは「not supported by osmem」で終わるエラーになります。analysis設定はインデックス作成時に検証します。インデックス作成と検索のトークン化は引き続きbleveベースのアナライザで行います。standard、simple、whitespace、keyword、stop、patternと、bleveの言語別アナライザ、トークナイザ(standard、whitespace、keyword、letter、pattern、ngram、edge_ngram、char_group、uax_url_email)、トークンフィルタ(lowercase、asciifolding、stop、ngram、edge_ngram、shingle、stemmer、snowball、porter_stem、truncate、length、unique、reverse、cjk_bigram、cjk_width)、文字フィルタ(html_strip、pattern_replace)から組み立てるカスタムアナライザ、normalizer。日本語サポートを有効にすれば、kuromojiアナライザ、モードとユーザー辞書に対応したkuromoji_tokenizer、kuromoji_baseform、kuromoji_part_of_speech、cjk_width、ja_stop、kuromoji_stemmer、kuromoji_readingform。
近似しているもの
Section titled “近似しているもの”- スコア。 bleveのBM25は、Luceneのものとは違います。普通のクエリなら順位は一致しますが、全文検索クエリの
_scoreの値と同点の扱いは一致しません。フィルタやterm系クエリなど定数スコアの部分はOpenSearchと同じです。 - 数値のrangeとsortの精度。 整数フィールドのterm検索は完全な値を使いますが、非常に大きな
longのrange検索とsortでは2^53を超える精度が失われることがあります。 - textのfielddata。
fielddata:trueなら、解析後のtermによるtext fieldのsortができます。fielddataを使ったtext aggregationは未対応で、fielddataを有効にしていないtext fieldのsortはエラーになります。 - 効果のない検索オプション。
timeoutとstatsは検証しますが効果はありません。profileはタイミングが0のOpenSearchと同じ構造を返し、名前付きのsearch_pipelineは存在している必要があります。runtime_mappingsは拒否します。 - アナライザ。 インデックス作成はbleveのアナライザを使うため、同じアナライザでも
_analyzeが返すトークンと実際に索引されるtermが異なることがあります。言語別アナライザは、bleveのステマーとストップワードを使います。日本語の分かち書きはkuromojiではなく、IPA辞書を使うkagomeによるもので、未知語では結果が異なることがあります。韓国語と中国語はCJKのbigramです。インデックス作成が実装していないカスタムアナライザのコンポーネントは、警告を出して読み飛ばします。 - 厳密さ。 OpenSearchはcardinalityを近似値で返しますが、osmemは厳密な値を返します。percentilesはOpenSearchと同じt-digestアルゴリズムですが、centroidが統合されるデータでは値がわずかに異なることがあります。
- 事前集計した文書数。 osmemのバケット集計は
_doc_countを無視します。OpenSearchでは_doc_countで事前集計済み文書の件数を反映できます。 - shardとrouting。 応答は設定したshard数を報告し、
terminate_afterとsliceもOpenSearchのshard単位の規則に従います。get・exists・delete・update・mgetと単一文書の読み書きは、複数shardのindexではOpenSearchと同じrouting hashを計算し、誤った、または未指定のroutingを本物の誤ったshardと同じく「見つからない」扱いにします。文書storeを(routing, id)で物理的に再構成してはいないため、同じ_idを別のroutingで書き込むと、別shardで共存するのではなく既存の1文書を更新します。 - リフレッシュ。 書き込みは即座に見えます。書き込みからリフレッシュまでの間の状態を、テストで観測することはできません。
- エラーのスタックトレース。
error_trace=trueを指定すると、OpenSearchと同様にosmemがレンダーするすべてのエラーとそのroot_cause・caused_byの各エントリにstack_traceが付与されますが、実際のJavaのスタックトレースではなく、例外名だけを含む単一の自作フレームです。
既知の動作差
Section titled “既知の動作差”以下は、このページの末尾にある差分監査の後も残っている差です。
| 領域 | 差 |
|---|---|
| フィールド型 | Luceneの決定化の上限を超えるregexpを拒否しません。textとshingleフィールドへのexistsクエリのヒット総数は、削除後に異なることがあります。BM25のk1/bパラメータは無視します。2^53を超えるlong値のsort値は精度が失われ、composite集計のunsigned_longのbucket keyも同じ境界で1ずれることがあります。マッピングされたdate_rangeフィールドへのdate_histogramはhard_boundsを無視します。 |
| エラーの詳細 | リクエストボディに複数の問題がある場合、osmemはキーを文書中の順ではなくソート順に検査するため、OpenSearchと異なる問題を報告することがあります。まれに使われる原因の連鎖が異なる場合があります。_mtermvectorsは非推奨のパラメータ別名(_version_type、camelCase名)をOpenSearchのように拒否しません。 |
| explanation | explain=true、_explain、Validate Queryのexplanationは、定数スコアのクエリとそのboolean組み合わせについて出力します。BM25とfunction_scoreのexplanationは再現しません。preference=_only_nodes:はノードを選ばずに受理し、_geo_distanceのソート値は末尾の桁が異なることがあります。 |
| 統計とノード | _stats、_cat、クラスタ統計のカウンタは0で、ストアサイズは推定値です。 |
| 集計 | JSONのキー順を保持しないため、複数キーのorderオブジェクトや、1リクエスト内でのaggsとaggregationsの優先が異なることがあります。マッピングが食い違う複数indexにまたがる集計は、OpenSearchがshard単位の結果を返す場合でも失敗することがあります。osmemは単一の検索ストリームなので、termsのshard_sizeは効果がありません。集計のprofileは常にサブ集計0件を報告します。 |
| ハイライト | tags_schemaとpre_tagsの両方を指定すると、キーの順番に関係なくtags_schemaが優先されます。top_hitsのハイライトはクエリのtermを使いません。index.highlight.max_analyzed_offsetとboundary_scanner_localeは未実装です。 |
| サジェスター | completion suggestionの応答は一致したcontextsを含みません。typed_keysはcompletion・phrase suggestionの名前にprefixを付けません。completionフィールドのcontextsマッピングは、OpenSearchの正規化形式(解決済みgeohash精度、大文字のtype)ではなく入力時の値(距離文字列そのまま、小文字のtype)をそのまま返します。 |
| その他のAPI | search templateと_rank_evalにはrouteがありません。_mtermvectorsと_termvectorsは、既にindexされた文書のみに対応し、その場で解析するdoc/per_field_analyzerモードは未対応です。 |
PIT検索では期限を確認し、検索リクエストにkeep_aliveがあれば延長します。
文書を書き換えるPainlessスクリプト(scriptによる更新のctx._source、scriptを使う_update_by_query/_reindex)や文書をまたいで集約するPainlessスクリプト(scripted_metric)、オブジェクト・配列型のscript params、バケット集計や値ソース集計でフィールドの代わりにscriptを使うこと、moving_fn(scriptにvalues配列引数を渡す手段が組み込みランタイムにまだない)、significant termsのscript_heuristic、kNNとニューラル検索、パーコレーター、children/parent集計とjoinクエリのinner_hits、ほとんどのspanクエリ(span_or、span_first、span_not、span_containing、span_within、field_masking_span)、実際のgeo_shape型フィールドに対するgeo_shape(bounding boxによる近似のみ。geo_pointフィールドへのgeo_shapeクエリは実装済み、「クエリ」を参照)、percentilesのhdr method、matrix_stats、geohex_grid、derivedフィールド、search template、rank evaluation、_list/indices、_list/shards、ingestパイプライン(パイプラインを参照する書き込みは「pipeline with id [x] does not exist」で失敗)、data stream、rollover、shrink/split/clone、_tasks、セキュリティ、スナップショット、_nodes/stats、_nodes/usage、hot threads、YAML・CBOR・SMILEのリクエストボディと応答(format=yaml)。
OpenSearchより厳しい点: 可搬な名前
Section titled “OpenSearchより厳しい点: 可搬な名前”osmemはOpenSearchが受け付ける入力の一部を拒否します。osmemで通るテストが、Amazon OpenSearch Serviceのmanagedドメインでも、Amazon OpenSearch Serverlessでも通るようにするためです。
.で始まるインデックス名は、400invalid_index_name_exception(「must not start with ‘.’」)で失敗します。hiddenインデックスや自動作成も対象です。OpenSearchはdeprecation警告を出すだけですが、Serverlessはこの名前を拒否し、データアクセスポリシーでも指定できません。- エイリアス名も、
.で始まる場合と大文字を含む場合に失敗します(invalid_alias_name_exception)。OpenSearchにはエイリアスの小文字規則がありません。 - Serverlessの文字集合に収まらない名前には警告を出します(
WithWarnings、osmem-serverでは標準エラー)。先頭は[a-z0-9;&$%]、2文字目以降は[a-z0-9+.~=_;&$%-]です。日本語などの非ASCIIの名前は、この集合の外です。 .kibanaのようなドット始まりのフィクスチャを再現したい場合は、osmem.WithDotNames()または--allow-dot-namesで解除できます。
Serverlessモード
Section titled “Serverlessモード”osmem.WithServerless(osmem.ServerlessSearch | ServerlessTimeSeries | ServerlessVectorSearch)、または--serverless search|timeseries|vectorsearchを指定すると、さらに制限します。
- AWSの「Supported OpenSearch API operations」表にある操作だけをルーティングします。それ以外は、Serverlessと同じく空ボディの404を返します。
GET /、_refresh、scroll、_reindex、by-query系、_cluster、_nodes、_stats、open/close、レガシー_template、indices・aliases・templates以外の_catが該当します。 - 書き込みでの
refresh=true(値なしのrefreshを含む)とrefresh=wait_forは、400status_exception(「true refresh policy is not supported.」)で失敗します。 - Serverlessの文字集合に収まらない名前は、警告ではなく拒否になります。
- time seriesとvector searchのコレクションは、クライアント指定のドキュメントIDを拒否します。対象は
PUT _doc/{id}、_create/{id}、_update/{id}と、bulkの_id付きindex/create項目およびupdate項目です。いずれも400illegal_argument_exception(「Document ID is not supported in create/index operation request」)になります。 number_of_shards、number_of_replicas、refresh_intervalはServerlessが管理するため、指定すると警告を出します。_cat/indicesにはhealth列とstatus列がありません。
Serverlessはインデックス名の規則を公開していません。文字集合は、同サービスのAPIにあるリソース名のパターンから取っています。wait_forとupdateのエラー文言は、trueとcreate/indexの場合からの推定です。
クライアントごとの注意
Section titled “クライアントごとの注意”- opensearch-go v4はCIでテストしています。go-elasticsearch v8には、確認対象の
X-Elastic-Productヘッダを返します。 - olivere/elasticは
/_nodesをスニッフィングします。osmemはそこに実際のlistenアドレスを返します。 - Elasticsearch 7のバージョン文字列を要求するクライアントには、クラスタ設定
compatibility.override_main_response_version: trueを設定してください。GET /が7.10.2を返すようになります。 - エラーはOpenSearchと同じ
{"error": {"root_cause", "type", "reason", "caused_by", ...}, "status"}の形です。search_phase_execution_exception内のshard failure、入れ子の例外からroot causeを選ぶ規則、パースエラーの位置情報(reasonの[行:列]接頭辞とline/colフィールド。delete-by-query、reindexのsource、aliasのfilterのようにOpenSearchが再シリアライズするボディを含む)もOpenSearchに合わせています。未知のURLには文字列のerrorを持つ400を返します。誤ったメソッドにはAllowヘッダ付きのフラットな405を返し、OPTIONSには許可メソッドを返します。 - リクエストはOpenSearchのRESTレイヤーと同じように検査します。すべてのrouteで未知のURLパラメータを400で拒否し(候補の提示を含む)、パラメータ値を検証します。ボディにはJSONの
Content-Typeが必要で、ない場合は406です。JSONの重複キーは拒否し、filter_pathはエラー応答を絞り込みません。 - 応答の数値はJavaと同じ表記(
1.0、1.0E-4)です。float・half_float・scaled_floatのdoc valueは、sort値、集計、fields、docvalue_fieldsで保存時の精度を反映します。
OpenSearch本体には広範な2.19系REST API YAMLテスト集があります。実行にはOpenSearchのJavaテストフレームワークが必要なので、osmemのGoテストとしてそのまま動かすことはできません。osmemには上記の挙動を確認するGo回帰テストがありますが、YAML全体を実行する差分ランナーはまだありません。テストが証明するのは、そのテストがassertする挙動に限られます。
別のOpenSearch API Specification projectにもYAML storyとnpm run test:specのrunnerがあり、OPENSEARCH_URLで接続先を指定できます。ガイドのcoverage例ではverb/path組み合わせの約39%を評価しています。request/responseの形を確認する補助には使えます。本体2.19 RESTテスト集の方が複数操作を通じた動作ケースを多く含みますが、osmemで使うにはJava側のtest harnessを適応させる必要があります。
OpenSearch 3.8.0との実サーバー比較
Section titled “OpenSearch 3.8.0との実サーバー比較”2026-09-15、公式OpenSearch 3.8.0 Dockerサーバーとosmem handlerで32ケースを実行しました。エンジン修正後は、同じHTTP status・応答フィールドのassertが両方で通過しています。v0.1.3で見つけた12件の差は、対象ケースについて修正済みです。
| 領域 | 検証した挙動 |
|---|---|
| 書き込みvalidation | external versionとcreate、自動ID、sequence number条件の併用を拒否します。正常なexternal versionとcompare-and-setの書き込みは成功します。Bulkの不正なcreate条件も書き込み前に拒否します。 |
| Bulk | 2^53を超えるversionとsigned 64-bit最大値を保持し、overflowを拒否します。JSONの小数versionはゼロ方向へ切り捨てます。未知のaction metadataとupdateのversion指定はリクエスト全体を拒否し、後続actionが不正なら先行文書も書き込みません。 |
| Resolve index | indexとaliasを別の配列で返し、解決したindexの全aliasとhidden属性を返します。wildcard指定を順番に適用し、none,openはopen indexを返し、open,noneは空配列になります。hiddenだけではopen indexを展開しません。closed indexはclosed属性を返し、存在しない名前はリクエストを失敗させずに結果から除きます。 |
| Index template | composableが一致した場合はlegacyを適用しません。同priorityの重複検査は3.8の規則に従い、非重複pattern、異なるpriority、同名templateの更新は許可します。 |
3.8のtemplate重複検査は、patternから*を除いた文字列が相手のpatternに一致するかを調べます。同じprefixのlogs*と*2026のように、理論的には交差しても登録できる組み合わせがあり、osmemもこの規則に合わせています。
リポジトリのtestdata/compatibility/README.mdにfixture、実サーバーrunner、修正前後の応答記録の説明があります。go test -run '^TestCompatibilityProbes$' -count=1 -v .でosmem側の回帰検査を実行でき、通常のテストにも含まれます。3.8の全機能との互換を保証するものではなく、assertしていないエラーメッセージや応答フィールドには差が残り得ます。このページのその他の制限も引き続き適用されます。osmemはGET /でOpenSearch 3.8.0を報告します。
OpenSearch 3.8.0との差分監査
Section titled “OpenSearch 3.8.0との差分監査”2026-09-16に、同じリクエスト列をOpenSearch 3.8.0(基準)、OpenSearch 2.19.1、osmemへ送り、took、UUID、ノードID、自動生成された文書IDなどの変動する値を除いたうえで、HTTP statusと応答全体を比較する差分ハーネスを実行しました。477シナリオ(6,139リクエスト)で、検索、文書API、マッピングとフィールド型、集計、クエリDSL、ハイライト、クラスタとインデックスの管理、cat API、HTTP層の挙動(URLパラメータ、Content-Type、メソッド、filter_path)を扱っています。2つのOpenSearchの挙動が異なる場合は3.8.0に合わせました。
| 時点 | OpenSearch 3.8.0と異なるリクエスト | 差のあるシナリオ |
|---|---|---|
| 修正前 | 3,263 | 447 |
| 修正後 | 308 | 101 |
各修正には、OpenSearch 3.8.0の応答を期待値にしたGoの回帰テストを追加しています。残っている差の多くは既知の動作差と未対応に記載したもので、値を検証していないフィールド型、意図的に拒否している機能、osmemが集計しない統計値、BM25のスコア値です。差分ハーネスとシナリオファイルはリポジトリに含めていません。
続く2回目の監査では、OpenSearch本体のREST API YAMLテスト集(検索・集計・文書API・マッピング・クラスタ/index管理にまたがる314ファイル)を、YAML自体のアサーションではなく応答の直接比較でOpenSearch 3.8.0とosmemへ同様に再生しました。1,200シナリオ中495件に実際の差があり、intervals、suggest API、rare_terms/significant_terms/significant_text/auto_date_histogram/variable_width_histogram、more_like_this、distance_feature、geo_pointフィールドへのgeo_shape、spanクエリ、_search_shards、term vectors、routingによるshard不一致の検出を実装し、unsigned_long集計、date_rangeのbucket境界、動的なsearch.max_buckets設定、その他いくつかの小さな不具合を修正した結果、244件まで減らしました(_score/max_scoreの値のみの差と、集計のprofileタイミングのみの差は、いずれも上記で既に近似として記載済みのため除いています)。残った差は上記の各節に統合しています。このハーネスも(初回のものとは別に作成した2つ目ですが)リポジトリには含めていません。