|
jstests/core/fts_index3.js fails on the following line, expecting find() to produce 0 documents, but SBE produces 1. More precisely, SBE matches the updated document in the collection, {a: “hello”, b: 2} given the filter {b: 1, $text: {$search: "hello"}}. For reference, the classic engine produces the following plan:
"winningPlan" : {
|
"stage" : "TEXT",
|
"indexPrefix" : {
|
|
},
|
"indexName" : "a_text_b_1",
|
"parsedTextQuery" : {
|
"terms" : [
|
"hello"
|
],
|
"negatedTerms" : [ ],
|
"phrases" : [ ],
|
"negatedPhrases" : [ ]
|
},
|
"textIndexVersion" : 3,
|
"inputStage" : {
|
"stage" : "TEXT_MATCH",
|
"inputStage" : {
|
"stage" : "FETCH",
|
"inputStage" : {
|
"stage" : "IXSCAN",
|
"filter" : {
|
"b" : {
|
"$eq" : 1
|
}
|
},
|
"keyPattern" : {
|
"_fts" : "text",
|
"_ftsx" : 1,
|
"b" : 1
|
},
|
"indexName" : "a_text_b_1",
|
"isMultiKey" : false,
|
"isUnique" : false,
|
"isSparse" : false,
|
"isPartial" : false,
|
"indexVersion" : 2,
|
"direction" : "backward",
|
"indexBounds" : {
|
|
}
|
}
|
}
|
}
|
}
|
while SBE produces the following plan:
[1] filter {s8}
|
[1] textmatch s6 s8
|
[1] nlj [] [s5]
|
left
|
[1] unique [s5]
|
[1] union [s5] [
|
[s2] [1] nlj [] [s3, s4]
|
left
|
[1] project [s3 = KS(3C68656C6C6F00290104),
|
s4 = KS(3C68656C6C6F002E773594000104)]
|
[1] limit 1
|
[1] coscan
|
right
|
[1] ixseek s3 s4 s2 [] @\"5efc3d91-62ea-4d6d-bf16-167fd5c54353\" @\"a_text_b_1\" true ]
|
right
|
[1] limit 1
|
[1] seek s5 s6 s7 [] @\"5efc3d91-62ea-4d6d-bf16-167fd5c54353\"
|
Note the filter on the index scan in the classic engine ({b: {$eq: 1}}).
Logging some output during plan execution reveals why the SBE plan matches the document, but the classic engine does not. After we've updated the document to have a value of b: 2, our compound index has two keys: one for b = 1 and another for b = 2. Crucially, it appears that the constructed SBE plan does not filter out the index key corresponding to b = 2 whereas the classic engine does:
Classic output:
checking key { : "hello", : 1.1, : 1.0 } answer 1
|
passed filter; classic index scan key: { : "hello", : 1.1, : 1.0 } key pattern is { _fts: "text", _ftsx: 1, b: 1.0 }
|
got a match! doc { _id: ObjectId('604005a0f4a0832086e9c0c7'), a: "hello", b: 1.0 } query { terms: [ "hello" ], negatedTerms: [], phrases: [], negatedPhrases: [] }
|
checking key { : "hello", : 1.1, : 2.0 } answer 0
|
SBE output:
SBE logging keystring...3C68656C6C6F002B03199999999999A02B02040008
|
FTS query { terms: [ "hello" ], negatedTerms: [], phrases: [], negatedPhrases: [] }
|
SBE trying to match obj { _id: ObjectId('6040032434574915ffc83765'), a: "hello", b: 1.0 } result is 1
|
SBE logging keystring...3C68656C6C6F002B03199999999999A02B04040008
|
FTS query { terms: [ "hello" ], negatedTerms: [], phrases: [], negatedPhrases: [] }
|
SBE trying to match obj { _id: ObjectId('6040032434574915ffc83765'), a: "hello", b: 2.0 } result is 1
|
(the classic engine rejects the key { : "hello", : 1.1, : 2.0 } , whereas SBE matches it).
The issue is that the classic engine applies the index filter whereas SBE does not. It looks like Anton's patch for SERVER-54322 is going to change the way that text plans are constructed for SBE: by making the query planner responsible for building text plans instead of the constructor for a TEXT node, it looks likely that the SBE stage builder will correctly build an IXSCAN with a filter (support added in SERVER-52734). Because Anton's work may address this, I'm going to hold off on implementing a fix .
|