summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTor Egge <Tor.Egge@online.no>2022-09-10 21:35:00 +0200
committerTor Egge <Tor.Egge@online.no>2022-09-10 21:35:00 +0200
commit9f9cf315337f9df383acf734a3b790d1f5df985e (patch)
tree97a3018cc7daadea3235a91f66af2b365922f603
parent2b533a5bda75247b4cff2754c0d48bfd2909b87c (diff)
Factor out helper classes for dynamic docsum field writer.
-rw-r--r--searchsummary/src/vespa/searchsummary/docsummary/CMakeLists.txt3
-rw-r--r--searchsummary/src/vespa/searchsummary/docsummary/dynamicteaserdfw.cpp255
-rw-r--r--searchsummary/src/vespa/searchsummary/docsummary/juniper_dfw_explicit_item_data.h23
-rw-r--r--searchsummary/src/vespa/searchsummary/docsummary/juniper_dfw_query_item.cpp27
-rw-r--r--searchsummary/src/vespa/searchsummary/docsummary/juniper_dfw_query_item.h35
-rw-r--r--searchsummary/src/vespa/searchsummary/docsummary/juniper_dfw_term_visitor.cpp37
-rw-r--r--searchsummary/src/vespa/searchsummary/docsummary/juniper_dfw_term_visitor.h29
-rw-r--r--searchsummary/src/vespa/searchsummary/docsummary/juniper_query_adapter.cpp163
-rw-r--r--searchsummary/src/vespa/searchsummary/docsummary/juniper_query_adapter.h37
9 files changed, 355 insertions, 254 deletions
diff --git a/searchsummary/src/vespa/searchsummary/docsummary/CMakeLists.txt b/searchsummary/src/vespa/searchsummary/docsummary/CMakeLists.txt
index 8070bed8b03..27946336e90 100644
--- a/searchsummary/src/vespa/searchsummary/docsummary/CMakeLists.txt
+++ b/searchsummary/src/vespa/searchsummary/docsummary/CMakeLists.txt
@@ -17,7 +17,10 @@ vespa_add_library(searchsummary_docsummary OBJECT
empty_dfw.cpp
geoposdfw.cpp
getdocsumargs.cpp
+ juniper_dfw_query_item.cpp
+ juniper_dfw_term_visitor.cpp
juniper_input.cpp
+ juniper_query_adapter.cpp
juniperproperties.cpp
keywordextractor.cpp
linguisticsannotation.cpp
diff --git a/searchsummary/src/vespa/searchsummary/docsummary/dynamicteaserdfw.cpp b/searchsummary/src/vespa/searchsummary/docsummary/dynamicteaserdfw.cpp
index 74845853fce..591f053d1cb 100644
--- a/searchsummary/src/vespa/searchsummary/docsummary/dynamicteaserdfw.cpp
+++ b/searchsummary/src/vespa/searchsummary/docsummary/dynamicteaserdfw.cpp
@@ -1,16 +1,11 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "juniperdfw.h"
-#include "docsumwriter.h"
#include "docsumstate.h"
#include "i_docsum_store_document.h"
-#include "keywordextractor.h"
-#include <vespa/searchlib/parsequery/stackdumpiterator.h>
-#include <vespa/searchlib/queryeval/split_float.h>
+#include "juniper_query_adapter.h"
#include <vespa/vespalib/objects/hexdump.h>
#include <vespa/juniper/config.h>
-#include <vespa/juniper/queryhandle.h>
-#include <vespa/juniper/query_item.h>
#include <vespa/juniper/result.h>
#include <vespa/vespalib/data/slime/inserter.h>
#include <sstream>
@@ -20,254 +15,6 @@ LOG_SETUP(".searchlib.docsummary.dynamicteaserdfw");
namespace search::docsummary {
-struct ExplicitItemData
-{
- vespalib::stringref _index;
- int32_t _weight;
-
- ExplicitItemData()
- : _index(), _weight(0)
- {}
-};
-
-
-
-/**
- * This struct is used to point to the traversal state located on
- * the stack of the IQuery Traverse method. This is needed because
- * the Traverse method is const.
- **/
-class JuniperDFWQueryItem : public juniper::QueryItem
-{
- search::SimpleQueryStackDumpIterator *_si;
- const ExplicitItemData *_data;
-public:
- JuniperDFWQueryItem() : _si(nullptr), _data(nullptr) {}
- ~JuniperDFWQueryItem() override = default;
- explicit JuniperDFWQueryItem(search::SimpleQueryStackDumpIterator *si) : _si(si), _data(nullptr) {}
- explicit JuniperDFWQueryItem(const ExplicitItemData *data) : _si(nullptr), _data(data) {}
- JuniperDFWQueryItem(const QueryItem&) = delete;
- JuniperDFWQueryItem& operator= (const QueryItem&) = delete;
-
- vespalib::stringref get_index() const override;
- int get_weight() const override;
- juniper::ItemCreator get_creator() const override;
-};
-
-vespalib::stringref
-JuniperDFWQueryItem::get_index() const
-{
- return _si != nullptr ? _si->getIndexName() : _data->_index;
-}
-
-int
-JuniperDFWQueryItem::get_weight() const
-{
- return _si != nullptr ? _si->GetWeight().percent() : _data->_weight;
-}
-
-juniper::ItemCreator
-JuniperDFWQueryItem::get_creator() const
-{
- return _si != nullptr ? _si->getCreator() : juniper::ItemCreator::CREA_ORIG;
-}
-
-class TermVisitor : public search::fef::IPropertiesVisitor
-{
-public:
- juniper::IQueryVisitor *_visitor;
- JuniperDFWQueryItem _item;
-
- explicit TermVisitor(juniper::IQueryVisitor *visitor)
- : _visitor(visitor),
- _item()
- {}
- void visitProperty(const search::fef::Property::Value &key, const search::fef::Property &values) override;
-
-};
-
-void
-TermVisitor::visitProperty(const search::fef::Property::Value &key, const search::fef::Property &values)
-{
- ExplicitItemData data;
- JuniperDFWQueryItem item(&data);
- int index = 0;
- int numBlocks = atoi(values.getAt(index++).c_str());
- data._index = key;
-
- _visitor->VisitAND(&item, numBlocks);
-
- for (int i = 0; i < numBlocks; i++) {
- const search::fef::Property::Value * s = & values.getAt(index++);
- if ((*s)[0] == '"') {
- s = & values.getAt(index++);
- int phraseLen = atoi(s->c_str());
- _visitor->VisitPHRASE(&item, phraseLen);
- s = & values.getAt(index++);
- while ((*s)[0] != '"') {
- _visitor->VisitKeyword(&item, s->c_str(), s->length());
- s = & values.getAt(index++);
- }
- } else {
- _visitor->VisitKeyword(&item, s->c_str(), s->length());
- }
- }
-}
-
-class JuniperQueryAdapter : public juniper::IQuery
-{
-private:
- KeywordExtractor *_kwExtractor;
- const vespalib::stringref _buf;
- const search::fef::Properties *_highlightTerms;
-
-public:
- JuniperQueryAdapter(const JuniperQueryAdapter&) = delete;
- JuniperQueryAdapter operator= (const JuniperQueryAdapter&) = delete;
- JuniperQueryAdapter(KeywordExtractor *kwExtractor, vespalib::stringref buf,
- const search::fef::Properties *highlightTerms = nullptr)
- : _kwExtractor(kwExtractor), _buf(buf), _highlightTerms(highlightTerms) {}
-
- // TODO: put this functionality into the stack dump iterator
- bool SkipItem(search::SimpleQueryStackDumpIterator *iterator) const
- {
- uint32_t skipCount = iterator->getArity();
-
- while (skipCount > 0) {
- if (!iterator->next())
- return false; // stack too small
- skipCount = skipCount - 1 + iterator->getArity();
- }
- return true;
- }
-
- bool Traverse(juniper::IQueryVisitor *v) const override;
-
- bool UsefulIndex(const juniper::QueryItem* item) const override
- {
- if (_kwExtractor == nullptr) {
- return true;
- }
- auto index = item->get_index();
- return _kwExtractor->IsLegalIndex(index);
- }
-};
-
-bool
-JuniperQueryAdapter::Traverse(juniper::IQueryVisitor *v) const
-{
- bool rc = true;
- search::SimpleQueryStackDumpIterator iterator(_buf);
- JuniperDFWQueryItem item(&iterator);
-
- if (_highlightTerms->numKeys() > 0) {
- v->VisitAND(&item, 2);
- }
- while (rc && iterator.next()) {
- bool isSpecialToken = iterator.hasSpecialTokenFlag();
- switch (iterator.getType()) {
- case search::ParseItem::ITEM_OR:
- case search::ParseItem::ITEM_WEAK_AND:
- case search::ParseItem::ITEM_EQUIV:
- case search::ParseItem::ITEM_WORD_ALTERNATIVES:
- if (!v->VisitOR(&item, iterator.getArity()))
- rc = SkipItem(&iterator);
- break;
- case search::ParseItem::ITEM_AND:
- if (!v->VisitAND(&item, iterator.getArity()))
- rc = SkipItem(&iterator);
- break;
- case search::ParseItem::ITEM_NOT:
- if (!v->VisitANDNOT(&item, iterator.getArity()))
- rc = SkipItem(&iterator);
- break;
- case search::ParseItem::ITEM_RANK:
- if (!v->VisitRANK(&item, iterator.getArity()))
- rc = SkipItem(&iterator);
- break;
- case search::ParseItem::ITEM_TERM:
- case search::ParseItem::ITEM_EXACTSTRINGTERM:
- case search::ParseItem::ITEM_PURE_WEIGHTED_STRING:
- {
- vespalib::stringref term = iterator.getTerm();
- v->VisitKeyword(&item, term.data(), term.size(), false, isSpecialToken);
- }
- break;
- case search::ParseItem::ITEM_NUMTERM:
- {
- vespalib::string term = iterator.getTerm();
- queryeval::SplitFloat splitter(term);
- if (splitter.parts() > 1) {
- if (v->VisitPHRASE(&item, splitter.parts())) {
- for (size_t i = 0; i < splitter.parts(); ++i) {
- v->VisitKeyword(&item,
- splitter.getPart(i).c_str(),
- splitter.getPart(i).size(), false);
- }
- }
- } else if (splitter.parts() == 1) {
- v->VisitKeyword(&item,
- splitter.getPart(0).c_str(),
- splitter.getPart(0).size(), false);
- } else {
- v->VisitKeyword(&item, term.c_str(), term.size(), false, true);
- }
- }
- break;
- case search::ParseItem::ITEM_PHRASE:
- if (!v->VisitPHRASE(&item, iterator.getArity()))
- rc = SkipItem(&iterator);
- break;
- case search::ParseItem::ITEM_PREFIXTERM:
- case search::ParseItem::ITEM_SUBSTRINGTERM:
- {
- vespalib::stringref term = iterator.getTerm();
- v->VisitKeyword(&item, term.data(), term.size(), true, isSpecialToken);
- }
- break;
- case search::ParseItem::ITEM_ANY:
- if (!v->VisitANY(&item, iterator.getArity()))
- rc = SkipItem(&iterator);
- break;
- case search::ParseItem::ITEM_NEAR:
- if (!v->VisitNEAR(&item, iterator.getArity(),iterator.getNearDistance()))
- rc = SkipItem(&iterator);
- break;
- case search::ParseItem::ITEM_ONEAR:
- if (!v->VisitWITHIN(&item, iterator.getArity(),iterator.getNearDistance()))
- rc = SkipItem(&iterator);
- break;
- case search::ParseItem::ITEM_TRUE:
- case search::ParseItem::ITEM_FALSE:
- break;
- // Unhandled items are just ignored by juniper
- case search::ParseItem::ITEM_WAND:
- case search::ParseItem::ITEM_WEIGHTED_SET:
- case search::ParseItem::ITEM_DOT_PRODUCT:
- case search::ParseItem::ITEM_PURE_WEIGHTED_LONG:
- case search::ParseItem::ITEM_SUFFIXTERM:
- case search::ParseItem::ITEM_REGEXP:
- case search::ParseItem::ITEM_PREDICATE_QUERY:
- case search::ParseItem::ITEM_SAME_ELEMENT:
- case search::ParseItem::ITEM_NEAREST_NEIGHBOR:
- case search::ParseItem::ITEM_GEO_LOCATION_TERM:
- if (!v->VisitOther(&item, iterator.getArity())) {
- rc = SkipItem(&iterator);
- }
- break;
- default:
- rc = false;
- }
- }
-
- if (_highlightTerms->numKeys() > 1) {
- v->VisitAND(&item, _highlightTerms->numKeys());
- }
- TermVisitor tv(v);
- _highlightTerms->visitProperties(tv);
-
- return rc;
-}
JuniperDFW::JuniperDFW(const juniper::Juniper * juniper)
: _input_field_name(),
diff --git a/searchsummary/src/vespa/searchsummary/docsummary/juniper_dfw_explicit_item_data.h b/searchsummary/src/vespa/searchsummary/docsummary/juniper_dfw_explicit_item_data.h
new file mode 100644
index 00000000000..aaa342e7d70
--- /dev/null
+++ b/searchsummary/src/vespa/searchsummary/docsummary/juniper_dfw_explicit_item_data.h
@@ -0,0 +1,23 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <vespa/vespalib/stllike/string.h>
+
+namespace search::docsummary {
+
+/*
+ * Explicit values used when JuniperDFWQueryItem doesn't have a query
+ * stack dump iterator.
+ */
+struct JuniperDFWExplicitItemData
+{
+ vespalib::stringref _index;
+ int32_t _weight;
+
+ JuniperDFWExplicitItemData()
+ : _index(), _weight(0)
+ {}
+};
+
+}
diff --git a/searchsummary/src/vespa/searchsummary/docsummary/juniper_dfw_query_item.cpp b/searchsummary/src/vespa/searchsummary/docsummary/juniper_dfw_query_item.cpp
new file mode 100644
index 00000000000..589d6eaabfb
--- /dev/null
+++ b/searchsummary/src/vespa/searchsummary/docsummary/juniper_dfw_query_item.cpp
@@ -0,0 +1,27 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "juniper_dfw_query_item.h"
+#include "juniper_dfw_explicit_item_data.h"
+#include <vespa/searchlib/parsequery/stackdumpiterator.h>
+
+namespace search::docsummary {
+
+vespalib::stringref
+JuniperDFWQueryItem::get_index() const
+{
+ return _si != nullptr ? _si->getIndexName() : _data->_index;
+}
+
+int
+JuniperDFWQueryItem::get_weight() const
+{
+ return _si != nullptr ? _si->GetWeight().percent() : _data->_weight;
+}
+
+juniper::ItemCreator
+JuniperDFWQueryItem::get_creator() const
+{
+ return _si != nullptr ? _si->getCreator() : juniper::ItemCreator::CREA_ORIG;
+}
+
+}
diff --git a/searchsummary/src/vespa/searchsummary/docsummary/juniper_dfw_query_item.h b/searchsummary/src/vespa/searchsummary/docsummary/juniper_dfw_query_item.h
new file mode 100644
index 00000000000..bec71b2e6fe
--- /dev/null
+++ b/searchsummary/src/vespa/searchsummary/docsummary/juniper_dfw_query_item.h
@@ -0,0 +1,35 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <vespa/juniper/query_item.h>
+
+namespace search { class SimpleQueryStackDumpIterator; }
+
+namespace search::docsummary {
+
+struct JuniperDFWExplicitItemData;
+
+/**
+ * This struct is used to point to the traversal state located on
+ * the stack of the IQuery Traverse method. This is needed because
+ * the Traverse method is const.
+ **/
+class JuniperDFWQueryItem : public juniper::QueryItem
+{
+ search::SimpleQueryStackDumpIterator *_si;
+ const JuniperDFWExplicitItemData *_data;
+public:
+ JuniperDFWQueryItem() : _si(nullptr), _data(nullptr) {}
+ ~JuniperDFWQueryItem() override = default;
+ explicit JuniperDFWQueryItem(search::SimpleQueryStackDumpIterator *si) : _si(si), _data(nullptr) {}
+ explicit JuniperDFWQueryItem(const JuniperDFWExplicitItemData *data) : _si(nullptr), _data(data) {}
+ JuniperDFWQueryItem(const QueryItem&) = delete;
+ JuniperDFWQueryItem& operator= (const QueryItem&) = delete;
+
+ vespalib::stringref get_index() const override;
+ int get_weight() const override;
+ juniper::ItemCreator get_creator() const override;
+};
+
+}
diff --git a/searchsummary/src/vespa/searchsummary/docsummary/juniper_dfw_term_visitor.cpp b/searchsummary/src/vespa/searchsummary/docsummary/juniper_dfw_term_visitor.cpp
new file mode 100644
index 00000000000..54db3ed6d0b
--- /dev/null
+++ b/searchsummary/src/vespa/searchsummary/docsummary/juniper_dfw_term_visitor.cpp
@@ -0,0 +1,37 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "juniper_dfw_term_visitor.h"
+#include "juniper_dfw_explicit_item_data.h"
+#include <vespa/juniper/query.h>
+
+namespace search::docsummary {
+
+void
+JuniperDFWTermVisitor::visitProperty(const search::fef::Property::Value &key, const search::fef::Property &values)
+{
+ JuniperDFWExplicitItemData data;
+ JuniperDFWQueryItem item(&data);
+ int index = 0;
+ int numBlocks = atoi(values.getAt(index++).c_str());
+ data._index = key;
+
+ _visitor->VisitAND(&item, numBlocks);
+
+ for (int i = 0; i < numBlocks; i++) {
+ const search::fef::Property::Value * s = & values.getAt(index++);
+ if ((*s)[0] == '"') {
+ s = & values.getAt(index++);
+ int phraseLen = atoi(s->c_str());
+ _visitor->VisitPHRASE(&item, phraseLen);
+ s = & values.getAt(index++);
+ while ((*s)[0] != '"') {
+ _visitor->VisitKeyword(&item, s->c_str(), s->length());
+ s = & values.getAt(index++);
+ }
+ } else {
+ _visitor->VisitKeyword(&item, s->c_str(), s->length());
+ }
+ }
+}
+
+}
diff --git a/searchsummary/src/vespa/searchsummary/docsummary/juniper_dfw_term_visitor.h b/searchsummary/src/vespa/searchsummary/docsummary/juniper_dfw_term_visitor.h
new file mode 100644
index 00000000000..4b8b3dd8e7b
--- /dev/null
+++ b/searchsummary/src/vespa/searchsummary/docsummary/juniper_dfw_term_visitor.h
@@ -0,0 +1,29 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include "juniper_dfw_query_item.h"
+#include <vespa/searchlib/fef/properties.h>
+
+namespace juniper { class IQueryVisitor; }
+
+namespace search::docsummary {
+
+/*
+ * Visitor used by juniper query adapter to visit properties describing
+ * terms to highlight.
+ */
+class JuniperDFWTermVisitor : public search::fef::IPropertiesVisitor
+{
+public:
+ juniper::IQueryVisitor *_visitor;
+ JuniperDFWQueryItem _item;
+
+ explicit JuniperDFWTermVisitor(juniper::IQueryVisitor *visitor)
+ : _visitor(visitor),
+ _item()
+ {}
+ void visitProperty(const search::fef::Property::Value &key, const search::fef::Property &values) override;
+};
+
+}
diff --git a/searchsummary/src/vespa/searchsummary/docsummary/juniper_query_adapter.cpp b/searchsummary/src/vespa/searchsummary/docsummary/juniper_query_adapter.cpp
new file mode 100644
index 00000000000..814fe0aafe4
--- /dev/null
+++ b/searchsummary/src/vespa/searchsummary/docsummary/juniper_query_adapter.cpp
@@ -0,0 +1,163 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "juniper_query_adapter.h"
+#include "juniper_dfw_query_item.h"
+#include "juniper_dfw_term_visitor.h"
+#include "keywordextractor.h"
+#include <vespa/searchlib/fef/properties.h>
+#include <vespa/searchlib/parsequery/stackdumpiterator.h>
+#include <vespa/searchlib/queryeval/split_float.h>
+
+namespace search::docsummary {
+
+JuniperQueryAdapter::JuniperQueryAdapter(KeywordExtractor *kwExtractor, vespalib::stringref buf,
+ const search::fef::Properties *highlightTerms)
+ : _kwExtractor(kwExtractor),
+ _buf(buf),
+ _highlightTerms(highlightTerms)
+{
+}
+
+JuniperQueryAdapter::~JuniperQueryAdapter() = default;
+
+// TODO: put this functionality into the stack dump iterator
+bool
+JuniperQueryAdapter::SkipItem(search::SimpleQueryStackDumpIterator *iterator) const
+{
+ uint32_t skipCount = iterator->getArity();
+
+ while (skipCount > 0) {
+ if (!iterator->next())
+ return false; // stack too small
+ skipCount = skipCount - 1 + iterator->getArity();
+ }
+ return true;
+}
+
+bool
+JuniperQueryAdapter::Traverse(juniper::IQueryVisitor *v) const
+{
+ bool rc = true;
+ search::SimpleQueryStackDumpIterator iterator(_buf);
+ JuniperDFWQueryItem item(&iterator);
+
+ if (_highlightTerms->numKeys() > 0) {
+ v->VisitAND(&item, 2);
+ }
+ while (rc && iterator.next()) {
+ bool isSpecialToken = iterator.hasSpecialTokenFlag();
+ switch (iterator.getType()) {
+ case search::ParseItem::ITEM_OR:
+ case search::ParseItem::ITEM_WEAK_AND:
+ case search::ParseItem::ITEM_EQUIV:
+ case search::ParseItem::ITEM_WORD_ALTERNATIVES:
+ if (!v->VisitOR(&item, iterator.getArity()))
+ rc = SkipItem(&iterator);
+ break;
+ case search::ParseItem::ITEM_AND:
+ if (!v->VisitAND(&item, iterator.getArity()))
+ rc = SkipItem(&iterator);
+ break;
+ case search::ParseItem::ITEM_NOT:
+ if (!v->VisitANDNOT(&item, iterator.getArity()))
+ rc = SkipItem(&iterator);
+ break;
+ case search::ParseItem::ITEM_RANK:
+ if (!v->VisitRANK(&item, iterator.getArity()))
+ rc = SkipItem(&iterator);
+ break;
+ case search::ParseItem::ITEM_TERM:
+ case search::ParseItem::ITEM_EXACTSTRINGTERM:
+ case search::ParseItem::ITEM_PURE_WEIGHTED_STRING:
+ {
+ vespalib::stringref term = iterator.getTerm();
+ v->VisitKeyword(&item, term.data(), term.size(), false, isSpecialToken);
+ }
+ break;
+ case search::ParseItem::ITEM_NUMTERM:
+ {
+ vespalib::string term = iterator.getTerm();
+ queryeval::SplitFloat splitter(term);
+ if (splitter.parts() > 1) {
+ if (v->VisitPHRASE(&item, splitter.parts())) {
+ for (size_t i = 0; i < splitter.parts(); ++i) {
+ v->VisitKeyword(&item,
+ splitter.getPart(i).c_str(),
+ splitter.getPart(i).size(), false);
+ }
+ }
+ } else if (splitter.parts() == 1) {
+ v->VisitKeyword(&item,
+ splitter.getPart(0).c_str(),
+ splitter.getPart(0).size(), false);
+ } else {
+ v->VisitKeyword(&item, term.c_str(), term.size(), false, true);
+ }
+ }
+ break;
+ case search::ParseItem::ITEM_PHRASE:
+ if (!v->VisitPHRASE(&item, iterator.getArity()))
+ rc = SkipItem(&iterator);
+ break;
+ case search::ParseItem::ITEM_PREFIXTERM:
+ case search::ParseItem::ITEM_SUBSTRINGTERM:
+ {
+ vespalib::stringref term = iterator.getTerm();
+ v->VisitKeyword(&item, term.data(), term.size(), true, isSpecialToken);
+ }
+ break;
+ case search::ParseItem::ITEM_ANY:
+ if (!v->VisitANY(&item, iterator.getArity()))
+ rc = SkipItem(&iterator);
+ break;
+ case search::ParseItem::ITEM_NEAR:
+ if (!v->VisitNEAR(&item, iterator.getArity(),iterator.getNearDistance()))
+ rc = SkipItem(&iterator);
+ break;
+ case search::ParseItem::ITEM_ONEAR:
+ if (!v->VisitWITHIN(&item, iterator.getArity(),iterator.getNearDistance()))
+ rc = SkipItem(&iterator);
+ break;
+ case search::ParseItem::ITEM_TRUE:
+ case search::ParseItem::ITEM_FALSE:
+ break;
+ // Unhandled items are just ignored by juniper
+ case search::ParseItem::ITEM_WAND:
+ case search::ParseItem::ITEM_WEIGHTED_SET:
+ case search::ParseItem::ITEM_DOT_PRODUCT:
+ case search::ParseItem::ITEM_PURE_WEIGHTED_LONG:
+ case search::ParseItem::ITEM_SUFFIXTERM:
+ case search::ParseItem::ITEM_REGEXP:
+ case search::ParseItem::ITEM_PREDICATE_QUERY:
+ case search::ParseItem::ITEM_SAME_ELEMENT:
+ case search::ParseItem::ITEM_NEAREST_NEIGHBOR:
+ case search::ParseItem::ITEM_GEO_LOCATION_TERM:
+ if (!v->VisitOther(&item, iterator.getArity())) {
+ rc = SkipItem(&iterator);
+ }
+ break;
+ default:
+ rc = false;
+ }
+ }
+
+ if (_highlightTerms->numKeys() > 1) {
+ v->VisitAND(&item, _highlightTerms->numKeys());
+ }
+ JuniperDFWTermVisitor tv(v);
+ _highlightTerms->visitProperties(tv);
+
+ return rc;
+}
+
+bool
+JuniperQueryAdapter::UsefulIndex(const juniper::QueryItem* item) const
+{
+ if (_kwExtractor == nullptr) {
+ return true;
+ }
+ auto index = item->get_index();
+ return _kwExtractor->IsLegalIndex(index);
+}
+
+}
diff --git a/searchsummary/src/vespa/searchsummary/docsummary/juniper_query_adapter.h b/searchsummary/src/vespa/searchsummary/docsummary/juniper_query_adapter.h
new file mode 100644
index 00000000000..18886ca2007
--- /dev/null
+++ b/searchsummary/src/vespa/searchsummary/docsummary/juniper_query_adapter.h
@@ -0,0 +1,37 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <vespa/juniper/query.h>
+#include <vespa/vespalib/stllike/string.h>
+
+namespace search { class SimpleQueryStackDumpIterator; }
+namespace search::fef { class Properties; }
+
+namespace search::docsummary {
+
+class KeywordExtractor;
+
+/*
+ * Class implementing an adapter used by juniper to examine the current
+ * query.
+ */
+class JuniperQueryAdapter : public juniper::IQuery
+{
+private:
+ KeywordExtractor *_kwExtractor;
+ const vespalib::stringref _buf;
+ const search::fef::Properties *_highlightTerms;
+
+public:
+ JuniperQueryAdapter(const JuniperQueryAdapter&) = delete;
+ JuniperQueryAdapter operator= (const JuniperQueryAdapter&) = delete;
+ JuniperQueryAdapter(KeywordExtractor *kwExtractor, vespalib::stringref buf,
+ const search::fef::Properties *highlightTerms = nullptr);
+ ~JuniperQueryAdapter() override;
+ bool SkipItem(search::SimpleQueryStackDumpIterator *iterator) const;
+ bool Traverse(juniper::IQueryVisitor *v) const override;
+ bool UsefulIndex(const juniper::QueryItem* item) const override;
+};
+
+}