SERVER-82020: BACKPORT-25616 [v8.2]: Enable hybrid search feature flag and upgrade/downgrade testing (#39468)
Co-authored-by: Finley Lau <finley.lau@mongodb.com> Co-authored-by: Mariano Shaar <mariano.shaar@mongodb.com> GitOrigin-RevId: 6e5c812d221048df48014948cc841e034a4873fc
This commit is contained in:
parent
8387f4eb6a
commit
675d0b61d2
@ -9,7 +9,8 @@
|
||||
* @tags: [
|
||||
* featureFlagRankFusionFull,
|
||||
* featureFlagSearchHybridScoringFull,
|
||||
* do_not_wrap_aggregations_in_facets
|
||||
* do_not_wrap_aggregations_in_facets,
|
||||
* requires_fcv_82
|
||||
* ]
|
||||
*/
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
* $scoreFusion and $score exists inside of jstests/with_mongot/e2e/hybridSearch. This test exists
|
||||
* in order to get picked up by the fuzzer/query shape hash stability tests (tests must exist inside
|
||||
* of the jstests/aggregation directory).
|
||||
* @tags: [ featureFlagSearchHybridScoringFull, do_not_wrap_aggregations_in_facets, requires_fcv_81
|
||||
* @tags: [ featureFlagSearchHybridScoringFull, do_not_wrap_aggregations_in_facets, requires_fcv_82
|
||||
* ]
|
||||
*/
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Test that $minMaxScaler window function output values are as expected.
|
||||
* @tags: [featureFlagSearchHybridScoringFull, requires_fcv_81]
|
||||
* @tags: [featureFlagSearchHybridScoringFull, requires_fcv_82]
|
||||
*/
|
||||
|
||||
const coll = db[jsTestName()];
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Test that $minMaxScaler window function expression parsing works.
|
||||
* @tags: [featureFlagSearchHybridScoringFull, requires_fcv_81]
|
||||
* @tags: [featureFlagSearchHybridScoringFull, requires_fcv_82]
|
||||
*/
|
||||
|
||||
const coll = db[jsTestName()];
|
||||
|
||||
@ -18,6 +18,8 @@ const coll = testDb[collName];
|
||||
coll.drop();
|
||||
coll.insert({a: 1});
|
||||
|
||||
const kUnrecognizedPipelineStageErrorCode = 40324;
|
||||
|
||||
const unstablePipelines = [
|
||||
[{$collStats: {count: {}, latencyStats: {}}}],
|
||||
[{$currentOp: {}}],
|
||||
@ -42,71 +44,47 @@ if (is81orAbove(db)) {
|
||||
unstablePipelines.push([{$listClusterCatalog: {}}]);
|
||||
}
|
||||
|
||||
// TODO SERVER-85426 $rankFusion can always be included when the feature flag is removed.
|
||||
// TODO SERVER-98591 Change RankFusionFull to RankFusionBasic.
|
||||
if (FeatureFlagUtil.isPresentAndEnabled(testDb.getMongo(), 'RankFusionFull')) {
|
||||
unstablePipelines.push([{$rankFusion: {input: {pipelines: {field1: [{$sort: {foo: 1}}]}}}}]);
|
||||
}
|
||||
unstablePipelines.push([{$rankFusion: {input: {pipelines: {field1: [{$sort: {foo: 1}}]}}}}]);
|
||||
|
||||
// TODO SERVER-82020: $scoreFusion/$score/$minMaxScaler can always be included when the feature flag
|
||||
// is enabled by default.
|
||||
if (FeatureFlagUtil.isPresentAndEnabled(testDb.getMongo(), 'SearchHybridScoringFull')) {
|
||||
let hybridSearchPipelines = [
|
||||
// $score is not included in the strict api.
|
||||
[{$score: {score: 10}}],
|
||||
// $minMaxScaler is not included in the strict api.
|
||||
[{
|
||||
$setWindowFields: {
|
||||
sortBy: {_id: 1},
|
||||
output: {
|
||||
"relativeXValue": {
|
||||
$minMaxScaler: {
|
||||
input: "$x",
|
||||
},
|
||||
window: {range: ["unbounded", "unbounded"]}
|
||||
let hybridSearchPipelines = [
|
||||
// $score is not included in the strict api.
|
||||
[{$score: {score: 10}}],
|
||||
// $minMaxScaler is not included in the strict api.
|
||||
[{
|
||||
$setWindowFields: {
|
||||
sortBy: {_id: 1},
|
||||
output: {
|
||||
"relativeXValue": {
|
||||
$minMaxScaler: {
|
||||
input: "$x",
|
||||
},
|
||||
}
|
||||
}
|
||||
}],
|
||||
// $scoreFusion is not included in the strict api.
|
||||
[{
|
||||
$scoreFusion: {
|
||||
input: {
|
||||
pipelines: {
|
||||
score2: [
|
||||
{
|
||||
$search: {
|
||||
index: "search_index",
|
||||
text: {query: "mystery", path: "genres"}
|
||||
}
|
||||
},
|
||||
{$match: {author: "dave"}}
|
||||
]
|
||||
},
|
||||
normalization: "none"
|
||||
window: {range: ["unbounded", "unbounded"]}
|
||||
},
|
||||
combination: {weights: {score2: 5}}
|
||||
}
|
||||
}]
|
||||
];
|
||||
}
|
||||
}],
|
||||
// $scoreFusion is not included in the strict api.
|
||||
[{
|
||||
$scoreFusion: {
|
||||
input: {
|
||||
pipelines: {
|
||||
score2: [
|
||||
{
|
||||
$search:
|
||||
{index: "search_index", text: {query: "mystery", path: "genres"}}
|
||||
},
|
||||
{$match: {author: "dave"}}
|
||||
]
|
||||
},
|
||||
normalization: "none"
|
||||
},
|
||||
combination: {weights: {score2: 5}}
|
||||
}
|
||||
}]
|
||||
];
|
||||
|
||||
for (var hybridSearchPipeline of hybridSearchPipelines) {
|
||||
// Hybrid search stages require a minimum FCV of 8.1. In some tests, namely
|
||||
// fcv_upgrade_downgrade_replica_sets_jscore_passthrough and its burn-in tests, the FCV is
|
||||
// changed in the background as the test is running. This results in a flaky test, unless we
|
||||
// accept both the strict API error code and the queryFeatureNotAllowed error code for
|
||||
// hybrid search pipelines.
|
||||
assert.commandFailedWithCode(
|
||||
testDb.runCommand({
|
||||
aggregate: collName,
|
||||
pipeline: hybridSearchPipeline,
|
||||
cursor: {},
|
||||
apiStrict: true,
|
||||
apiVersion: "1"
|
||||
}),
|
||||
[ErrorCodes.APIStrictError, ErrorCodes.QueryFeatureNotAllowed]);
|
||||
}
|
||||
}
|
||||
unstablePipelines.concat(hybridSearchPipelines);
|
||||
|
||||
function assertAggregateFailsWithAPIStrict(pipeline) {
|
||||
assert.commandFailedWithCode(testDb.runCommand({
|
||||
@ -116,7 +94,7 @@ function assertAggregateFailsWithAPIStrict(pipeline) {
|
||||
apiStrict: true,
|
||||
apiVersion: "1"
|
||||
}),
|
||||
ErrorCodes.APIStrictError);
|
||||
[ErrorCodes.APIStrictError, kUnrecognizedPipelineStageErrorCode]);
|
||||
}
|
||||
|
||||
for (let pipeline of unstablePipelines) {
|
||||
@ -124,6 +102,8 @@ for (let pipeline of unstablePipelines) {
|
||||
assertAggregateFailsWithAPIStrict(pipeline);
|
||||
|
||||
// Assert error thrown when creating a view on a pipeline with stages not in API Version 1.
|
||||
// The error code may also be an unrecognized pipeline stage, if the test is running in a
|
||||
// multiversioned scenario.
|
||||
assert.commandFailedWithCode(testDb.runCommand({
|
||||
create: 'api_version_pipeline_stages_should_fail',
|
||||
viewOn: collName,
|
||||
@ -131,7 +111,7 @@ for (let pipeline of unstablePipelines) {
|
||||
apiStrict: true,
|
||||
apiVersion: "1"
|
||||
}),
|
||||
ErrorCodes.APIStrictError);
|
||||
[ErrorCodes.APIStrictError, kUnrecognizedPipelineStageErrorCode]);
|
||||
}
|
||||
|
||||
// Test that $collStats is allowed in APIVersion 1, even with 'apiStrict: true', so long as the only
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
load("//bazel:mongo_js_rules.bzl", "mongo_js_library")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
mongo_js_library(
|
||||
name = "all_javascript_files",
|
||||
srcs = glob([
|
||||
"*.js",
|
||||
]),
|
||||
)
|
||||
@ -0,0 +1,5 @@
|
||||
version: 2.0.0
|
||||
filters:
|
||||
- "*":
|
||||
approvers:
|
||||
- 10gen/query-integration-search
|
||||
@ -11,8 +11,14 @@ import {
|
||||
|
||||
const collName = jsTestName();
|
||||
const getDB = (primaryConnection) => primaryConnection.getDB(jsTestName());
|
||||
const docs = [{_id: 0, foo: "xyz"}, {_id: 1, foo: "bar"}, {_id: 2, foo: "mongodb"}];
|
||||
|
||||
const viewName = "rank_fusion_view";
|
||||
|
||||
// This is a simple view pipeline that we will attempt to run $rankFusion queries on.
|
||||
const viewPipeline = [{$match: {_id: {$gt: 0}}}];
|
||||
|
||||
// TODO SERVER-108470 Add tests for $rankFusion with multiple input pipelines.
|
||||
const rankFusionPipeline = [{$rankFusion: {input: {pipelines: {field: [{$sort: {foo: 1}}]}}}}];
|
||||
const rankFusionPipelineWithScoreDetails = [
|
||||
{$rankFusion: {input: {pipelines: {field: [{$sort: {foo: 1}}]}}, scoreDetails: true}},
|
||||
@ -20,7 +26,6 @@ const rankFusionPipelineWithScoreDetails = [
|
||||
];
|
||||
|
||||
const kUnrecognizedPipelineStageErrorCode = 40324;
|
||||
|
||||
function setupCollection(primaryConn, shardingTest = null) {
|
||||
const coll = assertDropAndRecreateCollection(getDB(primaryConn), collName);
|
||||
|
||||
@ -28,8 +33,7 @@ function setupCollection(primaryConn, shardingTest = null) {
|
||||
shardingTest.shardColl(coll, {_id: 1});
|
||||
}
|
||||
|
||||
assert.commandWorked(
|
||||
coll.insertMany([{_id: 0, foo: "xyz"}, {_id: 1, foo: "bar"}, {_id: 2, foo: "mongodb"}]));
|
||||
assert.commandWorked(coll.insertMany(docs));
|
||||
}
|
||||
|
||||
function assertRankFusionCompletelyRejected(primaryConn) {
|
||||
@ -47,7 +51,6 @@ function assertRankFusionCompletelyRejected(primaryConn) {
|
||||
{aggregate: collName, pipeline: rankFusionPipelineWithScoreDetails, cursor: {}}),
|
||||
[kUnrecognizedPipelineStageErrorCode, ErrorCodes.QueryFeatureNotAllowed]);
|
||||
|
||||
// TODO SERVER-101721 Remove "OptionNotSupportedOnView" once $rankFusion in view is enabled.
|
||||
// View creation is rejected when view pipeline has $rankFusion.
|
||||
assert.commandFailedWithCode(db.createView(viewName, collName, rankFusionPipeline), [
|
||||
kUnrecognizedPipelineStageErrorCode,
|
||||
@ -60,6 +63,12 @@ function assertRankFusionCompletelyRejected(primaryConn) {
|
||||
ErrorCodes.QueryFeatureNotAllowed,
|
||||
ErrorCodes.OptionNotSupportedOnView
|
||||
]);
|
||||
|
||||
// Running $rankFusion against a view is rejected.
|
||||
assert.commandWorked(db.createView(viewName, collName, viewPipeline));
|
||||
assert.commandFailedWithCode(
|
||||
db.runCommand({aggregate: viewName, pipeline: rankFusionPipeline, cursor: {}}),
|
||||
[kUnrecognizedPipelineStageErrorCode, ErrorCodes.OptionNotSupportedOnView]);
|
||||
}
|
||||
|
||||
function assertRankFusionCompletelyAccepted(primaryConn) {
|
||||
@ -74,31 +83,7 @@ function assertRankFusionCompletelyAccepted(primaryConn) {
|
||||
assert.commandWorked(db.runCommand(
|
||||
{aggregate: collName, pipeline: rankFusionPipelineWithScoreDetails, cursor: {}}));
|
||||
|
||||
// TODO SERVER-101721 Enable $rankFusion to be run in a view definition.
|
||||
assert.commandFailedWithCode(db.createView(viewName, collName, rankFusionPipeline),
|
||||
[ErrorCodes.OptionNotSupportedOnView]);
|
||||
assert.commandFailedWithCode(
|
||||
db.createView(viewName, collName, rankFusionPipelineWithScoreDetails),
|
||||
[ErrorCodes.OptionNotSupportedOnView]);
|
||||
/**
|
||||
assert.commandWorked(db.createView(viewName, collName, rankFusionPipeline));
|
||||
assert.commandWorked(
|
||||
db.runCommand({aggregate: viewName, pipeline: [{$match: {_id: {$gt: 0}}}], cursor: {}}));
|
||||
*/
|
||||
}
|
||||
|
||||
function assertRankFusionAcceptedButNotInView(primaryConn) {
|
||||
const db = getDB(primaryConn);
|
||||
db[viewName].drop();
|
||||
|
||||
// $rankFusion succeeds in an aggregation command, but view creation is rejection with
|
||||
// $rankFusion in the view pipeline.
|
||||
assert.commandWorked(
|
||||
db.runCommand({aggregate: collName, pipeline: rankFusionPipeline, cursor: {}}));
|
||||
assert.commandWorked(db.runCommand(
|
||||
{aggregate: collName, pipeline: rankFusionPipelineWithScoreDetails, cursor: {}}));
|
||||
|
||||
// TODO SERVER-101721 Remove "OptionNotSupportedOnView" once $rankFusion in view is enabled.
|
||||
// View creation is rejected when view pipeline has $rankFusion.
|
||||
assert.commandFailedWithCode(db.createView(viewName, collName, rankFusionPipeline), [
|
||||
kUnrecognizedPipelineStageErrorCode,
|
||||
ErrorCodes.QueryFeatureNotAllowed,
|
||||
@ -110,6 +95,13 @@ function assertRankFusionAcceptedButNotInView(primaryConn) {
|
||||
ErrorCodes.QueryFeatureNotAllowed,
|
||||
ErrorCodes.OptionNotSupportedOnView
|
||||
]);
|
||||
|
||||
// Running $rankFusion against a view succeeds.
|
||||
assert.commandWorked(db.createView(viewName, collName, viewPipeline));
|
||||
assert.commandWorked(
|
||||
db.runCommand({aggregate: viewName, pipeline: rankFusionPipeline, cursor: {}}));
|
||||
assert.commandWorked(db.runCommand(
|
||||
{aggregate: viewName, pipeline: rankFusionPipelineWithScoreDetails, cursor: {}}));
|
||||
}
|
||||
|
||||
testPerformUpgradeDowngradeReplSet({
|
||||
@ -126,6 +118,9 @@ testPerformUpgradeDowngradeSharded({
|
||||
whenOnlyConfigIsLatestBinary: assertRankFusionCompletelyRejected,
|
||||
whenSecondariesAndConfigAreLatestBinary: assertRankFusionCompletelyRejected,
|
||||
whenMongosBinaryIsLastLTS: assertRankFusionCompletelyRejected,
|
||||
whenBinariesAreLatestAndFCVIsLastLTS: assertRankFusionAcceptedButNotInView,
|
||||
// TODO SERVER-108470 This should completely reject $rankFusion, however because mongos is not
|
||||
// FCV-aware, it is non-trivial to detect that $rankFusion should be rejected here on the
|
||||
// shards.
|
||||
whenBinariesAreLatestAndFCVIsLastLTS: assertRankFusionCompletelyAccepted,
|
||||
whenFullyUpgraded: assertRankFusionCompletelyAccepted,
|
||||
});
|
||||
@ -0,0 +1,205 @@
|
||||
/**
|
||||
* Verifies that $scoreFusion behaves correctly in FCV upgrade/downgrade scenarios.
|
||||
*/
|
||||
import {assertDropAndRecreateCollection} from "jstests/libs/collection_drop_recreate.js";
|
||||
import {
|
||||
testPerformUpgradeDowngradeReplSet
|
||||
} from "jstests/multiVersion/libs/mixed_version_fixture_test.js";
|
||||
import {
|
||||
testPerformUpgradeDowngradeSharded
|
||||
} from "jstests/multiVersion/libs/mixed_version_sharded_fixture_test.js";
|
||||
|
||||
const collName = jsTestName();
|
||||
const getDB = (primaryConnection) => primaryConnection.getDB(jsTestName());
|
||||
const viewName = collName + "_view";
|
||||
|
||||
const scoreFusionPipeline = [{
|
||||
$scoreFusion: {
|
||||
input: {
|
||||
pipelines:
|
||||
{otherField: [{$score: {score: "$bar"}}], field: [{$score: {score: "$foo"}}]},
|
||||
normalization: "minMaxScaler"
|
||||
}
|
||||
}
|
||||
}];
|
||||
const scoreFusionPipelineWithScoreDetails = [{
|
||||
$scoreFusion: {
|
||||
input: {
|
||||
pipelines:
|
||||
{otherField: [{$score: {score: "$bar"}}], field: [{$score: {score: "$foo"}}]},
|
||||
normalization: "none",
|
||||
},
|
||||
scoreDetails: true
|
||||
}
|
||||
}];
|
||||
|
||||
// This is a simple view pipeline that we will attempt to run $scoreFusion queries on.
|
||||
const viewPipeline = [{$match: {_id: {$gt: 0}}}];
|
||||
|
||||
const scorePipeline = [{$score: {score: "$foo"}}];
|
||||
const scorePipelineWithScoreDetails = [{$score: {score: "$foo", scoreDetails: true}}];
|
||||
|
||||
const projectStage = {
|
||||
$project: {scoreDetails: {$meta: "scoreDetails"}, score: {$meta: "score"}}
|
||||
};
|
||||
const scoreFusionPipelineWithProject = [...scoreFusionPipelineWithScoreDetails, projectStage];
|
||||
const scorePipelineWithProject = [...scorePipelineWithScoreDetails, projectStage];
|
||||
|
||||
const kUnrecognizedPipelineStageErrorCode = 40324;
|
||||
|
||||
function setupCollection(primaryConn, shardingTest = null) {
|
||||
const coll = assertDropAndRecreateCollection(getDB(primaryConn), collName);
|
||||
|
||||
if (shardingTest) {
|
||||
shardingTest.shardColl(coll, {_id: 1});
|
||||
}
|
||||
|
||||
assert.commandWorked(coll.insertMany(
|
||||
[{_id: 0, foo: 5, bar: 10}, {_id: 1, foo: 6, bar: 20}, {_id: 2, foo: 7, bar: 30}]));
|
||||
}
|
||||
|
||||
function assertScoreFusionCompletelyRejected(primaryConn) {
|
||||
const db = getDB(primaryConn);
|
||||
db[viewName].drop();
|
||||
|
||||
// Creating a view with $scoreFusion/$score is rejected.
|
||||
assert.commandFailedWithCode(
|
||||
db.createView("bad_score_fusion_view", collName, scoreFusionPipeline),
|
||||
[kUnrecognizedPipelineStageErrorCode, ErrorCodes.OptionNotSupportedOnView]);
|
||||
assert.commandFailedWithCode(
|
||||
db.createView("bad_score_view", collName, scorePipeline),
|
||||
[kUnrecognizedPipelineStageErrorCode, ErrorCodes.OptionNotSupportedOnView]);
|
||||
|
||||
// $scoreFusion/$score on a view is rejected.
|
||||
assert.commandWorked(db.createView(viewName, collName, viewPipeline));
|
||||
assert.commandFailedWithCode(
|
||||
db.runCommand({aggregate: viewName, pipeline: scoreFusionPipeline, cursor: {}}), [
|
||||
kUnrecognizedPipelineStageErrorCode,
|
||||
ErrorCodes.QueryFeatureNotAllowed,
|
||||
ErrorCodes.OptionNotSupportedOnView,
|
||||
ErrorCodes.FailedToParse
|
||||
]);
|
||||
assert.commandFailedWithCode(
|
||||
db.runCommand({aggregate: viewName, pipeline: scorePipeline, cursor: {}}), [
|
||||
kUnrecognizedPipelineStageErrorCode,
|
||||
ErrorCodes.QueryFeatureNotAllowed,
|
||||
ErrorCodes.OptionNotSupportedOnView,
|
||||
ErrorCodes.FailedToParse
|
||||
]);
|
||||
|
||||
// $projects referencing score and scoreDetails metadata are rejected in aggregation
|
||||
// commands.
|
||||
assert.commandFailedWithCode(db.runCommand({
|
||||
aggregate: collName,
|
||||
pipeline: [...scorePipelineWithScoreDetails, projectStage],
|
||||
cursor: {}
|
||||
}),
|
||||
[
|
||||
ErrorCodes.FailedToParse,
|
||||
ErrorCodes.QueryFeatureNotAllowed,
|
||||
kUnrecognizedPipelineStageErrorCode,
|
||||
17308
|
||||
]);
|
||||
assert.commandFailedWithCode(db.runCommand({
|
||||
aggregate: collName,
|
||||
pipeline: [...scorePipelineWithScoreDetails, projectStage],
|
||||
cursor: {}
|
||||
}),
|
||||
[
|
||||
ErrorCodes.FailedToParse,
|
||||
ErrorCodes.QueryFeatureNotAllowed,
|
||||
kUnrecognizedPipelineStageErrorCode,
|
||||
17308
|
||||
]);
|
||||
|
||||
// $scoreFusion is rejected in a plain aggregation command.
|
||||
assert.commandFailedWithCode(
|
||||
db.runCommand({aggregate: collName, pipeline: scoreFusionPipeline, cursor: {}}), [
|
||||
kUnrecognizedPipelineStageErrorCode,
|
||||
ErrorCodes.FailedToParse,
|
||||
ErrorCodes.QueryFeatureNotAllowed,
|
||||
]);
|
||||
|
||||
// $scoreFusion with scoreDetails is still rejected.
|
||||
assert.commandFailedWithCode(
|
||||
db.runCommand(
|
||||
{aggregate: collName, pipeline: scoreFusionPipelineWithScoreDetails, cursor: {}}),
|
||||
[
|
||||
kUnrecognizedPipelineStageErrorCode,
|
||||
ErrorCodes.FailedToParse,
|
||||
ErrorCodes.QueryFeatureNotAllowed,
|
||||
]);
|
||||
|
||||
// $score is rejected in a plain aggregation command.
|
||||
assert.commandFailedWithCode(
|
||||
db.runCommand({aggregate: collName, pipeline: scorePipeline, cursor: {}}), [
|
||||
kUnrecognizedPipelineStageErrorCode,
|
||||
ErrorCodes.FailedToParse,
|
||||
ErrorCodes.QueryFeatureNotAllowed,
|
||||
]);
|
||||
|
||||
// $score with scoreDetails is still rejected.
|
||||
assert.commandFailedWithCode(
|
||||
db.runCommand({aggregate: collName, pipeline: scorePipelineWithScoreDetails, cursor: {}}), [
|
||||
kUnrecognizedPipelineStageErrorCode,
|
||||
ErrorCodes.FailedToParse,
|
||||
ErrorCodes.QueryFeatureNotAllowed,
|
||||
]);
|
||||
}
|
||||
|
||||
function assertScoreFusionCompletelyAccepted(primaryConn) {
|
||||
const db = getDB(primaryConn);
|
||||
db[viewName].drop();
|
||||
|
||||
// Creating a view with $scoreFusion/$score is rejected.
|
||||
assert.commandFailedWithCode(
|
||||
db.createView("bad_score_fusion_view", collName, scoreFusionPipeline),
|
||||
[ErrorCodes.OptionNotSupportedOnView]);
|
||||
assert.commandFailedWithCode(db.createView("bad_score_view", collName, scorePipeline),
|
||||
[ErrorCodes.OptionNotSupportedOnView]);
|
||||
|
||||
// $scoreFusion/$score on a view works.
|
||||
assert.commandWorked(db.createView(viewName, collName, viewPipeline));
|
||||
assert.commandWorked(
|
||||
db.runCommand({aggregate: viewName, pipeline: scoreFusionPipeline, cursor: {}}));
|
||||
assert.commandWorked(db.runCommand({aggregate: viewName, pipeline: scorePipeline, cursor: {}}));
|
||||
|
||||
// $projects referencing score and scoreDetails metadata succeed in aggregation commands.
|
||||
assert.commandWorked(
|
||||
db.runCommand({aggregate: collName, pipeline: scoreFusionPipelineWithProject, cursor: {}}));
|
||||
assert.commandWorked(
|
||||
db.runCommand({aggregate: collName, pipeline: scorePipelineWithProject, cursor: {}}));
|
||||
|
||||
// $scoreFusion succeeds in an aggregation command.
|
||||
assert.commandWorked(
|
||||
db.runCommand({aggregate: collName, pipeline: scoreFusionPipeline, cursor: {}}));
|
||||
|
||||
// $scoreFusion with scoreDetails succeeds in an aggregation command.
|
||||
assert.commandWorked(db.runCommand(
|
||||
{aggregate: collName, pipeline: scoreFusionPipelineWithScoreDetails, cursor: {}}));
|
||||
|
||||
// $score succeeds in an aggregation command.
|
||||
assert.commandWorked(db.runCommand({aggregate: collName, pipeline: scorePipeline, cursor: {}}));
|
||||
|
||||
// $score with scoreDetails succeeds in an aggregation command.
|
||||
assert.commandWorked(
|
||||
db.runCommand({aggregate: collName, pipeline: scorePipelineWithScoreDetails, cursor: {}}));
|
||||
}
|
||||
|
||||
testPerformUpgradeDowngradeReplSet({
|
||||
setupFn: setupCollection,
|
||||
whenFullyDowngraded: assertScoreFusionCompletelyRejected,
|
||||
whenSecondariesAreLatestBinary: assertScoreFusionCompletelyRejected,
|
||||
whenBinariesAreLatestAndFCVIsLastLTS: assertScoreFusionCompletelyRejected,
|
||||
whenFullyUpgraded: assertScoreFusionCompletelyAccepted,
|
||||
});
|
||||
|
||||
testPerformUpgradeDowngradeSharded({
|
||||
setupFn: setupCollection,
|
||||
whenFullyDowngraded: assertScoreFusionCompletelyRejected,
|
||||
whenOnlyConfigIsLatestBinary: assertScoreFusionCompletelyRejected,
|
||||
whenSecondariesAndConfigAreLatestBinary: assertScoreFusionCompletelyRejected,
|
||||
whenMongosBinaryIsLastLTS: assertScoreFusionCompletelyRejected,
|
||||
whenBinariesAreLatestAndFCVIsLastLTS: assertScoreFusionCompletelyRejected,
|
||||
whenFullyUpgraded: assertScoreFusionCompletelyAccepted,
|
||||
});
|
||||
@ -8,7 +8,7 @@
|
||||
* featureFlagRankFusionFull,
|
||||
* # Needed for the nested $scoreFusion.
|
||||
* featureFlagSearchHybridScoringFull,
|
||||
* requires_fcv_81
|
||||
* requires_fcv_82
|
||||
* ]
|
||||
*/
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
/**
|
||||
* Tests that the $sample stage works reasonably within $rankFusion.
|
||||
*
|
||||
* @tags: [featureFlagSearchHybridScoringFull, requires_fcv_81]
|
||||
* @tags: [featureFlagSearchHybridScoringFull, requires_fcv_82]
|
||||
*/
|
||||
|
||||
import {assertErrorCode} from "jstests/aggregation/extras/utils.js";
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
* featureFlagRankFusionBasic,
|
||||
* featureFlagRankFusionFull,
|
||||
* featureFlagSearchHybridScoringFull,
|
||||
* requires_fcv_82
|
||||
* ]
|
||||
*/
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
* analysis in various pipeline structures and does not verify correctness of the scoreDetails field
|
||||
* contents itself.
|
||||
*
|
||||
* @tags: [ featureFlagRankFusionFull, featureFlagSearchHybridScoringFull, requires_fcv_81 ]
|
||||
* @tags: [ featureFlagRankFusionFull, featureFlagSearchHybridScoringFull, requires_fcv_82 ]
|
||||
*/
|
||||
|
||||
import {assertErrCodeAndErrMsgContains} from "jstests/aggregation/extras/utils.js";
|
||||
|
||||
@ -63,24 +63,7 @@ public:
|
||||
scopedGlobalServiceContextForTest = nullptr)
|
||||
: AggregationContextFixture(
|
||||
NamespaceString::createNamespaceString_forTest(boost::none, "test", "pipeline_test"),
|
||||
std::move(scopedGlobalServiceContextForTest)) {
|
||||
// TODO SERVER-82020: Delete this once the feature flag defaults to true.
|
||||
// $minMaxScaler is gated behind a feature flag and does
|
||||
// not get put into the map as the flag is off by default. Changing the value of the feature
|
||||
// flag with RAIIServerParameterControllerForTest() does not solve the issue because the
|
||||
// registration logic is not re-hit.
|
||||
try {
|
||||
window_function::Expression::registerParser(
|
||||
"$minMaxScaler",
|
||||
window_function::ExpressionMinMaxScaler::parse,
|
||||
nullptr,
|
||||
AllowedWithApiStrict::kNeverInVersion1);
|
||||
} catch (const DBException& e) {
|
||||
// Allow this exception, to allow multiple instances
|
||||
// to be created in this process.
|
||||
ASSERT_EQ(e.reason(), "Duplicate parsers ($minMaxScaler) registered.");
|
||||
}
|
||||
}
|
||||
std::move(scopedGlobalServiceContextForTest)) {}
|
||||
|
||||
explicit AggregationContextFixture(NamespaceString nss,
|
||||
std::unique_ptr<ScopedGlobalServiceContextForTest>
|
||||
|
||||
@ -46,24 +46,7 @@ namespace {
|
||||
class DocumentSourceScoreFusionTest : service_context_test::WithSetupTransportLayer,
|
||||
public AggregationContextFixture {
|
||||
public:
|
||||
DocumentSourceScoreFusionTest() {
|
||||
// TODO SERVER-82020: Delete this once the feature flag defaults to true.
|
||||
// $minMaxScaler is gated behind a feature flag and does
|
||||
// not get put into the map as the flag is off by default. Changing the value of the feature
|
||||
// flag with RAIIServerParameterControllerForTest() does not solve the issue because the
|
||||
// registration logic is not re-hit.
|
||||
try {
|
||||
window_function::Expression::registerParser(
|
||||
"$minMaxScaler",
|
||||
window_function::ExpressionMinMaxScaler::parse,
|
||||
nullptr,
|
||||
AllowedWithApiStrict::kNeverInVersion1);
|
||||
} catch (const DBException& e) {
|
||||
// Allow this exception, to allow multiple instances
|
||||
// to be created in this process.
|
||||
ASSERT(e.reason() == "Duplicate parsers ($minMaxScaler) registered.");
|
||||
}
|
||||
}
|
||||
DocumentSourceScoreFusionTest() {}
|
||||
|
||||
private:
|
||||
RAIIServerParameterControllerForTest scoreFusionFlag{"featureFlagSearchHybridScoringFull",
|
||||
|
||||
@ -187,8 +187,9 @@ feature_flags:
|
||||
|
||||
featureFlagRankFusionFull:
|
||||
description:
|
||||
"Feature flag to finish up $rankFusion features as well as introduce $score and
|
||||
$scoreDetails stages. (Second milestone of Vector Search Hybrid Scoring)"
|
||||
"Feature flag to finish up $rankFusion features as well as introduce score and
|
||||
scoreDetails metadata fields. $rankFusion will also begin to produce these metadata fields.
|
||||
(Second milestone of Vector Search Hybrid Scoring)"
|
||||
cpp_varname: gFeatureFlagRankFusionFull
|
||||
default: true
|
||||
version: 8.1
|
||||
@ -197,10 +198,11 @@ feature_flags:
|
||||
|
||||
featureFlagSearchHybridScoringFull:
|
||||
description:
|
||||
"Feature flag to introduce $scoreFusion, the $minMaxScaler helper and finish up
|
||||
"Feature flag to introduce $scoreFusion, $score, and the $minMaxScaler helper and finish up
|
||||
hybrid scoring features. (Final milestone of Vector Search Hybrid Scoring)"
|
||||
cpp_varname: gFeatureFlagSearchHybridScoringFull
|
||||
default: false
|
||||
default: true
|
||||
version: 8.2
|
||||
fcv_gated: true
|
||||
|
||||
featureFlagQueryMemoryTracking:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user