1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once
#include "andsearchnostrict.h"
#include <vespa/fastos/dynamiclibrary.h>
namespace search {
namespace queryeval {
/**
* A simple strict implementation of the And search operation.
**/
template <typename Unpack>
class AndSearchStrict : public AndSearchNoStrict<Unpack>
{
private:
template<bool doSeekOnly>
VESPA_DLL_LOCAL void advance(uint32_t failedChildIndexd) __attribute__((noinline));
using Trinary=vespalib::Trinary;
protected:
void doSeek(uint32_t docid) override;
Trinary is_strict() const override { return Trinary::True; }
SearchIterator::UP andWith(SearchIterator::UP filter, uint32_t estimate) override;
public:
AndSearchStrict(const MultiSearch::Children & children, const Unpack & unpacker) :
AndSearchNoStrict<Unpack>(children, unpacker)
{
}
void initRange(uint32_t beginid, uint32_t endid) override {
AndSearchNoStrict<Unpack>::initRange(beginid, endid);
advance<false>(0);
}
};
template<typename Unpack>
template<bool doSeekOnly>
void
AndSearchStrict<Unpack>::advance(uint32_t failedChildIndex)
{
const MultiSearch::Children & children(this->getChildren());
SearchIterator & firstChild(*children[0]);
bool foundHit(false);
if (failedChildIndex != 0) {
if (doSeekOnly) {
if (__builtin_expect(children[failedChildIndex]->isAtEnd(), false)) {
this->setAtEnd();
return;
}
firstChild.doSeek(std::max(firstChild.getDocId() + 1, children[failedChildIndex]->getDocId()));
} else {
firstChild.seek(std::max(firstChild.getDocId() + 1, children[failedChildIndex]->getDocId()));
}
}
uint32_t nextId(firstChild.getDocId());
while (!foundHit && !this->isAtEnd(nextId)) {
foundHit = true;
for (uint32_t i(1); foundHit && (i < children.size()); ++i) {
SearchIterator & child(*children[i]);
if (!(foundHit = child.seek(nextId))) {
if (__builtin_expect(!child.isAtEnd(), true)) {
firstChild.doSeek(std::max(nextId+1, child.getDocId()));
nextId = firstChild.getDocId();
} else {
this->setAtEnd();
return;
}
}
}
}
this->setDocId(nextId);
}
template<typename Unpack>
void
AndSearchStrict<Unpack>::doSeek(uint32_t docid)
{
const MultiSearch::Children & children(this->getChildren());
for (uint32_t i(0); i < children.size(); ++i) {
children[i]->doSeek(docid);
if (children[i]->getDocId() != docid) {
advance<true>(i);
return;
}
}
this->setDocId(docid);
}
template<typename Unpack>
SearchIterator::UP
AndSearchStrict<Unpack>::andWith(SearchIterator::UP filter, uint32_t estimate_)
{
filter = this->getChildren()[0]->andWith(std::move(filter), estimate_);
if (filter) {
if ((estimate_ < this->estimate()) && (filter->is_strict() == Trinary::True)) {
this->insert(0, std::move(filter));
} else {
filter = this->offerFilterToChildren(std::move(filter), estimate_);
if (filter) {
this->insert(1, std::move(filter));
}
}
}
return filter; // Should always be empty, returning it incase logic changes.
}
} // namespace queryeval
} // namespace search
|