data: split off inner classes of SearchIndex
This commit is contained in:
@@ -34,17 +34,17 @@ Storage.cpp INFO: function: main <input.cc 34:5 34:8>
|
|||||||
Storage.cpp INFO: type usage: main -> B <input.cc 36:2 36:2>
|
Storage.cpp INFO: type usage: main -> B <input.cc 36:2 36:2>
|
||||||
Storage.cpp INFO: call: main -> B::B <input.cc 36:4 36:4>
|
Storage.cpp INFO: call: main -> B::B <input.cc 36:4 36:4>
|
||||||
Storage.cpp INFO: call: main -> A::getCount <input.cc 38:9 38:21>
|
Storage.cpp INFO: call: main -> A::getCount <input.cc 38:9 38:21>
|
||||||
SearchIndex.cpp INFO:
|
SearchMatch.cpp INFO:
|
||||||
1 matches for "main":
|
1 matches for "main":
|
||||||
474 main
|
474 main
|
||||||
^^^^
|
^^^^
|
||||||
|
|
||||||
SearchIndex.cpp INFO:
|
SearchMatch.cpp INFO:
|
||||||
1 matches for "main":
|
1 matches for "main":
|
||||||
474 main
|
474 main
|
||||||
^^^^
|
^^^^
|
||||||
|
|
||||||
SearchIndex.cpp INFO:
|
SearchMatch.cpp INFO:
|
||||||
1 matches for "A::A":
|
1 matches for "A::A":
|
||||||
237 A::A
|
237 A::A
|
||||||
^^^^
|
^^^^
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ void QtSearchBar::setFocus()
|
|||||||
m_searchBox->setFocus();
|
m_searchBox->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtSearchBar::setAutocompletionList(const std::vector<SearchIndex::SearchMatch>& autocompletionList)
|
void QtSearchBar::setAutocompletionList(const std::vector<SearchMatch>& autocompletionList)
|
||||||
{
|
{
|
||||||
m_searchBox->setAutocompletionList(autocompletionList);
|
m_searchBox->setAutocompletionList(autocompletionList);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#include <QAbstractItemView>
|
#include <QAbstractItemView>
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
|
|
||||||
#include "data/SearchIndex.h"
|
#include "data/search/SearchMatch.h"
|
||||||
|
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
class QtSmartSearchBox;
|
class QtSmartSearchBox;
|
||||||
@@ -22,7 +22,7 @@ public:
|
|||||||
|
|
||||||
void setText(const std::string& text);
|
void setText(const std::string& text);
|
||||||
void setFocus();
|
void setFocus();
|
||||||
void setAutocompletionList(const std::vector<SearchIndex::SearchMatch>& autocompletionList);
|
void setAutocompletionList(const std::vector<SearchMatch>& autocompletionList);
|
||||||
|
|
||||||
QAbstractItemView* getCompleterPopup();
|
QAbstractItemView* getCompleterPopup();
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ QtSmartSearchBox::~QtSmartSearchBox()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtSmartSearchBox::setAutocompletionList(const std::vector<SearchIndex::SearchMatch>& autocompletionList)
|
void QtSmartSearchBox::setAutocompletionList(const std::vector<SearchMatch>& autocompletionList)
|
||||||
{
|
{
|
||||||
m_matches = autocompletionList;
|
m_matches = autocompletionList;
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ void QtSmartSearchBox::setAutocompletionList(const std::vector<SearchIndex::Sear
|
|||||||
}
|
}
|
||||||
|
|
||||||
QStringList wordList;
|
QStringList wordList;
|
||||||
for (const SearchIndex::SearchMatch& match: autocompletionList)
|
for (const SearchMatch& match: autocompletionList)
|
||||||
{
|
{
|
||||||
wordList << match.fullName.c_str();
|
wordList << match.fullName.c_str();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
#ifndef QT_SMART_SEARCH_BOX_H
|
#ifndef QT_SMART_SEARCH_BOX_H
|
||||||
#define QT_SMART_SEARCH_BOX_H
|
#define QT_SMART_SEARCH_BOX_H
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
|
||||||
#include "data/SearchIndex.h"
|
#include "data/search/SearchMatch.h"
|
||||||
|
|
||||||
class QtQueryElement
|
class QtQueryElement
|
||||||
: public QPushButton
|
: public QPushButton
|
||||||
@@ -37,7 +38,7 @@ public:
|
|||||||
QtSmartSearchBox(QWidget* parent);
|
QtSmartSearchBox(QWidget* parent);
|
||||||
virtual ~QtSmartSearchBox();
|
virtual ~QtSmartSearchBox();
|
||||||
|
|
||||||
void setAutocompletionList(const std::vector<SearchIndex::SearchMatch>& autocompletionList);
|
void setAutocompletionList(const std::vector<SearchMatch>& autocompletionList);
|
||||||
void setQuery(const std::string& text);
|
void setQuery(const std::string& text);
|
||||||
void setFocus();
|
void setFocus();
|
||||||
|
|
||||||
@@ -90,7 +91,7 @@ private:
|
|||||||
|
|
||||||
size_t m_cursorIndex;
|
size_t m_cursorIndex;
|
||||||
|
|
||||||
std::vector<SearchIndex::SearchMatch> m_matches;
|
std::vector<SearchMatch> m_matches;
|
||||||
|
|
||||||
bool m_shiftKeyDown;
|
bool m_shiftKeyDown;
|
||||||
bool m_mousePressed;
|
bool m_mousePressed;
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ void QtSearchView::setFocus()
|
|||||||
m_setFocusFunctor();
|
m_setFocusFunctor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtSearchView::setAutocompletionList(const std::vector<SearchIndex::SearchMatch>& autocompletionList)
|
void QtSearchView::setAutocompletionList(const std::vector<SearchMatch>& autocompletionList)
|
||||||
{
|
{
|
||||||
m_setAutocompletionListFunctor(autocompletionList);
|
m_setAutocompletionListFunctor(autocompletionList);
|
||||||
}
|
}
|
||||||
@@ -64,7 +64,7 @@ void QtSearchView::doSetFocus()
|
|||||||
m_widget->setFocus();
|
m_widget->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtSearchView::doSetAutocompletionList(const std::vector<SearchIndex::SearchMatch>& autocompletionList)
|
void QtSearchView::doSetAutocompletionList(const std::vector<SearchMatch>& autocompletionList)
|
||||||
{
|
{
|
||||||
m_widget->setAutocompletionList(autocompletionList);
|
m_widget->setAutocompletionList(autocompletionList);
|
||||||
setStyleSheet();
|
setStyleSheet();
|
||||||
|
|||||||
@@ -21,20 +21,20 @@ public:
|
|||||||
// SearchView implementation
|
// SearchView implementation
|
||||||
virtual void setText(const std::string& text);
|
virtual void setText(const std::string& text);
|
||||||
virtual void setFocus();
|
virtual void setFocus();
|
||||||
virtual void setAutocompletionList(const std::vector<SearchIndex::SearchMatch>& autocompletionList);
|
virtual void setAutocompletionList(const std::vector<SearchMatch>& autocompletionList);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void doRefreshView();
|
void doRefreshView();
|
||||||
void doSetText(const std::string& text);
|
void doSetText(const std::string& text);
|
||||||
void doSetFocus();
|
void doSetFocus();
|
||||||
void doSetAutocompletionList(const std::vector<SearchIndex::SearchMatch>& autocompletionList);
|
void doSetAutocompletionList(const std::vector<SearchMatch>& autocompletionList);
|
||||||
|
|
||||||
void setStyleSheet();
|
void setStyleSheet();
|
||||||
|
|
||||||
QtThreadedFunctor<> m_refreshViewFunctor;
|
QtThreadedFunctor<> m_refreshViewFunctor;
|
||||||
QtThreadedFunctor<const std::string&> m_setTextFunctor;
|
QtThreadedFunctor<const std::string&> m_setTextFunctor;
|
||||||
QtThreadedFunctor<> m_setFocusFunctor;
|
QtThreadedFunctor<> m_setFocusFunctor;
|
||||||
QtThreadedFunctor<const std::vector<SearchIndex::SearchMatch>&> m_setAutocompletionListFunctor;
|
QtThreadedFunctor<const std::vector<SearchMatch>&> m_setAutocompletionListFunctor;
|
||||||
|
|
||||||
std::shared_ptr<QtSearchBar> m_widget;
|
std::shared_ptr<QtSearchBar> m_widget;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -142,6 +142,15 @@ add_files(
|
|||||||
data/query/QueryTree.cpp
|
data/query/QueryTree.cpp
|
||||||
data/query/QueryTree.h
|
data/query/QueryTree.h
|
||||||
|
|
||||||
|
data/search/SearchIndex.cpp
|
||||||
|
data/search/SearchIndex.h
|
||||||
|
data/search/SearchNode.cpp
|
||||||
|
data/search/SearchNode.h
|
||||||
|
data/search/SearchMatch.cpp
|
||||||
|
data/search/SearchMatch.h
|
||||||
|
data/search/SearchResult.cpp
|
||||||
|
data/search/SearchResult.h
|
||||||
|
|
||||||
data/type/modifier/DataTypeModifier.cpp
|
data/type/modifier/DataTypeModifier.cpp
|
||||||
data/type/modifier/DataTypeModifier.h
|
data/type/modifier/DataTypeModifier.h
|
||||||
data/type/modifier/DataTypeModifierArray.cpp
|
data/type/modifier/DataTypeModifierArray.cpp
|
||||||
@@ -158,8 +167,6 @@ add_files(
|
|||||||
data/type/DataTypeQualifierList.cpp
|
data/type/DataTypeQualifierList.cpp
|
||||||
data/type/DataTypeQualifierList.h
|
data/type/DataTypeQualifierList.h
|
||||||
|
|
||||||
data/SearchIndex.cpp
|
|
||||||
data/SearchIndex.h
|
|
||||||
data/Storage.cpp
|
data/Storage.cpp
|
||||||
data/Storage.h
|
data/Storage.h
|
||||||
|
|
||||||
|
|||||||
@@ -18,10 +18,11 @@ void SearchController::handleMessage(MessageActivateToken* message)
|
|||||||
{
|
{
|
||||||
if (!m_ignoreNextMessageActivateToken && message->tokenId)
|
if (!m_ignoreNextMessageActivateToken && message->tokenId)
|
||||||
{
|
{
|
||||||
std::string name = m_graphAccess->getNameForNodeWithId(message->tokenId);
|
SearchMatch match;
|
||||||
std::stringstream ss;
|
match.fullName = m_graphAccess->getNameForNodeWithId(message->tokenId);
|
||||||
ss << '"' << name << ',' << message->tokenId << '"';
|
match.tokenIds.insert(message->tokenId);
|
||||||
getView()->setText(ss.str());
|
|
||||||
|
getView()->setText(match.encodeForQuery());
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ignoreNextMessageActivateToken = false;
|
m_ignoreNextMessageActivateToken = false;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#define SEARCH_VIEW_H
|
#define SEARCH_VIEW_H
|
||||||
|
|
||||||
#include "component/view/View.h"
|
#include "component/view/View.h"
|
||||||
#include "data/SearchIndex.h"
|
#include "data/search/SearchMatch.h"
|
||||||
|
|
||||||
class SearchController;
|
class SearchController;
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ public:
|
|||||||
|
|
||||||
virtual void setText(const std::string& s) = 0;
|
virtual void setText(const std::string& s) = 0;
|
||||||
virtual void setFocus() = 0;
|
virtual void setFocus() = 0;
|
||||||
virtual void setAutocompletionList(const std::vector<SearchIndex::SearchMatch>& autocompletionList) = 0;
|
virtual void setAutocompletionList(const std::vector<SearchMatch>& autocompletionList) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SearchController* getController();
|
SearchController* getController();
|
||||||
|
|||||||
@@ -1,465 +0,0 @@
|
|||||||
#include "data/SearchIndex.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cctype>
|
|
||||||
|
|
||||||
#include "data/query/QueryCommand.h"
|
|
||||||
#include "data/query/QueryToken.h"
|
|
||||||
#include "utility/logging/logging.h"
|
|
||||||
#include "utility/utilityString.h"
|
|
||||||
|
|
||||||
SearchIndex::SearchResult::SearchResult()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchIndex::SearchResult::SearchResult(
|
|
||||||
size_t weight,
|
|
||||||
const SearchIndex::SearchNode* node,
|
|
||||||
const SearchIndex::SearchNode* parent
|
|
||||||
)
|
|
||||||
: weight(weight)
|
|
||||||
, node(node)
|
|
||||||
, parent(parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SearchIndex::SearchResult::operator()(const SearchResult& lhs, const SearchResult& rhs) const
|
|
||||||
{
|
|
||||||
if (lhs.weight != rhs.weight)
|
|
||||||
{
|
|
||||||
return lhs.weight > rhs.weight;
|
|
||||||
}
|
|
||||||
|
|
||||||
return lhs.node->getFullName() < rhs.node->getFullName();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SearchIndex::SearchMatch::print(std::ostream& ostream) const
|
|
||||||
{
|
|
||||||
ostream << weight << '\t' << fullName << std::endl << '\t';
|
|
||||||
size_t i = 0;
|
|
||||||
for (size_t index : indices)
|
|
||||||
{
|
|
||||||
while (i < index)
|
|
||||||
{
|
|
||||||
i++;
|
|
||||||
ostream << ' ';
|
|
||||||
}
|
|
||||||
ostream << '^';
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
ostream << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string SearchIndex::SearchMatch::encodeForQuery() const
|
|
||||||
{
|
|
||||||
if (!tokenIds.size())
|
|
||||||
{
|
|
||||||
return QueryCommand::BOUNDARY + fullName + QueryCommand::BOUNDARY;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << QueryToken::BOUNDARY << fullName;
|
|
||||||
for (Id tokenId : tokenIds)
|
|
||||||
{
|
|
||||||
ss << QueryToken::DELIMITER << tokenId;
|
|
||||||
}
|
|
||||||
ss << QueryToken::BOUNDARY;
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchIndex::SearchNode::SearchNode(SearchNode* parent, const std::string& name, Id nameId)
|
|
||||||
: m_parent(parent)
|
|
||||||
, m_name(name)
|
|
||||||
, m_nameId(nameId)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchIndex::SearchNode::~SearchNode()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& SearchIndex::SearchNode::getName() const
|
|
||||||
{
|
|
||||||
return m_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string SearchIndex::SearchNode::getFullName() const
|
|
||||||
{
|
|
||||||
if (m_parent && m_parent->m_nameId)
|
|
||||||
{
|
|
||||||
return m_parent->getFullName() + DELIMITER + getName();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return getName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Id SearchIndex::SearchNode::getNameId() const
|
|
||||||
{
|
|
||||||
return m_nameId;
|
|
||||||
}
|
|
||||||
|
|
||||||
Id SearchIndex::SearchNode::getFirstTokenId() const
|
|
||||||
{
|
|
||||||
if (m_tokenIds.size())
|
|
||||||
{
|
|
||||||
return *m_tokenIds.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::set<Id>& SearchIndex::SearchNode::getTokenIds() const
|
|
||||||
{
|
|
||||||
return m_tokenIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SearchIndex::SearchNode::addTokenId(Id tokenId)
|
|
||||||
{
|
|
||||||
m_tokenIds.insert(tokenId);
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchIndex::SearchNode* SearchIndex::SearchNode::getParent() const
|
|
||||||
{
|
|
||||||
if (m_parent && m_parent->m_nameId)
|
|
||||||
{
|
|
||||||
return m_parent;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::deque<SearchIndex::SearchNode*> SearchIndex::SearchNode::getParentsWithoutTokenId()
|
|
||||||
{
|
|
||||||
std::deque<SearchNode*> nodes;
|
|
||||||
|
|
||||||
SearchNode* node = this;
|
|
||||||
while (node->m_nameId && !node->m_tokenIds.size())
|
|
||||||
{
|
|
||||||
nodes.push_front(node);
|
|
||||||
node = node->m_parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::set<std::shared_ptr<SearchIndex::SearchNode>>& SearchIndex::SearchNode::getChildren() const
|
|
||||||
{
|
|
||||||
return m_nodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchIndex::SearchResults SearchIndex::SearchNode::runFuzzySearch(const std::string& query, bool recursive) const
|
|
||||||
{
|
|
||||||
SearchResults result;
|
|
||||||
|
|
||||||
if (recursive)
|
|
||||||
{
|
|
||||||
for (std::shared_ptr<SearchNode> n: m_nodes)
|
|
||||||
{
|
|
||||||
FuzzyMap m = n->fuzzyMatchRecursive(query, 0, 0, 0);
|
|
||||||
for (const std::pair<size_t, const SearchNode*>& p : m)
|
|
||||||
{
|
|
||||||
result.insert(SearchResult(p.first, p.second, this));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::pair<size_t, size_t> p = fuzzyMatch(query, 0, 0);
|
|
||||||
size_t pos = p.first;
|
|
||||||
size_t weight = p.second;
|
|
||||||
|
|
||||||
if (pos == query.size())
|
|
||||||
{
|
|
||||||
result.insert(SearchResult(weight, this, this));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Currently all matches are added to the ordered set and get compared by their fullName for alphabetical
|
|
||||||
// order. This could be improved by limiting the number of items to e.g. 100.
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<SearchIndex::SearchNode> SearchIndex::SearchNode::addNodeRecursive(
|
|
||||||
std::deque<Id>* nameIds, const Dictionary& dictionary
|
|
||||||
){
|
|
||||||
Id nameId = nameIds->front();
|
|
||||||
nameIds->pop_front();
|
|
||||||
|
|
||||||
std::shared_ptr<SearchNode> node = getChildWithNameId(nameId);
|
|
||||||
if (!node)
|
|
||||||
{
|
|
||||||
node = std::make_shared<SearchNode>(this, dictionary.getWord(nameId), nameId);
|
|
||||||
m_nodes.insert(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nameIds->size() > 0)
|
|
||||||
{
|
|
||||||
return node->addNodeRecursive(nameIds, dictionary);
|
|
||||||
}
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<SearchIndex::SearchNode> SearchIndex::SearchNode::getNodeRecursive(std::deque<Id>* nameIds) const
|
|
||||||
{
|
|
||||||
Id nameId = nameIds->front();
|
|
||||||
nameIds->pop_front();
|
|
||||||
|
|
||||||
std::shared_ptr<SearchNode> node = getChildWithNameId(nameId);
|
|
||||||
if (node)
|
|
||||||
{
|
|
||||||
if (!nameIds->size())
|
|
||||||
{
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
return node->getNodeRecursive(nameIds);
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchIndex::SearchNode::FuzzyMap SearchIndex::SearchNode::fuzzyMatchRecursive(
|
|
||||||
const std::string& query, size_t pos, size_t weight, size_t size) const
|
|
||||||
{
|
|
||||||
FuzzyMap result;
|
|
||||||
std::pair<size_t, size_t> p = fuzzyMatch(query, pos, size);
|
|
||||||
pos = p.first;
|
|
||||||
weight += p.second;
|
|
||||||
|
|
||||||
if (pos == query.size())
|
|
||||||
{
|
|
||||||
result.emplace(weight, this);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::shared_ptr<SearchNode> n: m_nodes)
|
|
||||||
{
|
|
||||||
FuzzyMap m = n->fuzzyMatchRecursive(query, pos, weight, size + m_name.size() + SearchIndex::DELIMITER.size());
|
|
||||||
result.insert(m.begin(), m.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<size_t, size_t> SearchIndex::SearchNode::fuzzyMatch(
|
|
||||||
const std::string query, size_t start, size_t size, std::vector<size_t>* indices) const
|
|
||||||
{
|
|
||||||
size_t pos = start;
|
|
||||||
size_t weight = 0;
|
|
||||||
size_t matchCount = 0;
|
|
||||||
char lastChar = '\0';
|
|
||||||
|
|
||||||
size_t ql = query.size();
|
|
||||||
size_t ml = m_name.size();
|
|
||||||
|
|
||||||
if (!query.size())
|
|
||||||
{
|
|
||||||
return std::pair<size_t, size_t>(pos, weight);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (query[pos] == ':')
|
|
||||||
{
|
|
||||||
pos++;
|
|
||||||
if (indices && size >= 2)
|
|
||||||
{
|
|
||||||
indices->push_back(size - 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pos < ql && query[pos] == ':')
|
|
||||||
{
|
|
||||||
pos++;
|
|
||||||
if (indices && size >= 1)
|
|
||||||
{
|
|
||||||
indices->push_back(size - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < ml; i++)
|
|
||||||
{
|
|
||||||
char c = m_name[i];
|
|
||||||
if (tolower(query[pos]) == tolower(c))
|
|
||||||
{
|
|
||||||
weight += std::max<size_t>(100 - size - i, 1);
|
|
||||||
if (matchCount)
|
|
||||||
{
|
|
||||||
weight += matchCount * 10;
|
|
||||||
}
|
|
||||||
else if (i == 0 || lastChar == '_' || tolower(c) != c)
|
|
||||||
{
|
|
||||||
weight += 20;
|
|
||||||
}
|
|
||||||
matchCount++;
|
|
||||||
|
|
||||||
pos++;
|
|
||||||
if (indices)
|
|
||||||
{
|
|
||||||
indices->push_back(size + i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pos == ql || query[pos] == ':')
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
matchCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
lastChar = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::pair<size_t, size_t>(pos, weight);
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchIndex::SearchMatch SearchIndex::SearchNode::fuzzyMatchData(const std::string& query, const SearchNode* parent) const
|
|
||||||
{
|
|
||||||
SearchMatch data;
|
|
||||||
data.fullName = getFullName();
|
|
||||||
data.tokenIds = m_tokenIds;
|
|
||||||
data.weight = 0;
|
|
||||||
|
|
||||||
size_t pos = 0;
|
|
||||||
size_t size = 0;
|
|
||||||
|
|
||||||
std::deque<const SearchNode*> nodes = getNodesToParent(parent);
|
|
||||||
if (!nodes.size())
|
|
||||||
{
|
|
||||||
nodes.push_back(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const SearchNode* node : nodes)
|
|
||||||
{
|
|
||||||
std::pair<size_t, size_t> p = node->fuzzyMatch(query, pos, size, &data.indices);
|
|
||||||
pos = p.first;
|
|
||||||
data.weight += p.second;
|
|
||||||
size += node->m_name.size() + SearchIndex::DELIMITER.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<SearchIndex::SearchNode> SearchIndex::SearchNode::getChildWithNameId(Id nameId) const
|
|
||||||
{
|
|
||||||
for (std::shared_ptr<SearchNode> n: m_nodes)
|
|
||||||
{
|
|
||||||
if (n->m_nameId == nameId)
|
|
||||||
{
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::deque<const SearchIndex::SearchNode*> SearchIndex::SearchNode::getNodesToParent(const SearchNode* parent) const
|
|
||||||
{
|
|
||||||
std::deque<const SearchIndex::SearchNode*> nodes;
|
|
||||||
|
|
||||||
const SearchNode* node = this;
|
|
||||||
while (node->m_nameId && node != parent)
|
|
||||||
{
|
|
||||||
nodes.push_front(node);
|
|
||||||
node = node->m_parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<SearchIndex::SearchMatch> SearchIndex::getMatches(
|
|
||||||
const SearchIndex::SearchResults& searchResults,
|
|
||||||
const std::string& query
|
|
||||||
){
|
|
||||||
std::vector<SearchMatch> result;
|
|
||||||
|
|
||||||
for (SearchResultsIterator it = searchResults.begin(); it != searchResults.end(); it++)
|
|
||||||
{
|
|
||||||
SearchMatch match = it->node->fuzzyMatchData(query, it->parent);
|
|
||||||
result.push_back(match);
|
|
||||||
|
|
||||||
if (it->weight != match.weight)
|
|
||||||
{
|
|
||||||
LOG_ERROR("Weight between matching and meta data is different.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SearchIndex::logMatches(const std::vector<SearchIndex::SearchMatch>& matches, const std::string& query)
|
|
||||||
{
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << std::endl << matches.size() << " matches for \"" << query << "\":" << std::endl;
|
|
||||||
for (const SearchIndex::SearchMatch& match : matches)
|
|
||||||
{
|
|
||||||
match.print(ss);
|
|
||||||
}
|
|
||||||
LOG_INFO(ss.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchIndex::SearchIndex()
|
|
||||||
: m_root(nullptr, DELIMITER, 0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchIndex::~SearchIndex()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void SearchIndex::clear()
|
|
||||||
{
|
|
||||||
m_root.m_nodes.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
Id SearchIndex::getWordId(const std::string& word)
|
|
||||||
{
|
|
||||||
return m_dictionary.getWordId(word);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& SearchIndex::getWord(Id wordId) const
|
|
||||||
{
|
|
||||||
return m_dictionary.getWord(wordId);
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchIndex::SearchNode* SearchIndex::addNode(std::vector<std::string> nameHierarchy)
|
|
||||||
{
|
|
||||||
std::deque<Id> nameIds;
|
|
||||||
for (const std::string& name: nameHierarchy)
|
|
||||||
{
|
|
||||||
nameIds.push_back(m_dictionary.getWordId(name));
|
|
||||||
}
|
|
||||||
if (nameIds.size())
|
|
||||||
{
|
|
||||||
return m_root.addNodeRecursive(&nameIds, m_dictionary).get();
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchIndex::SearchNode* SearchIndex::getNode(const std::string& fullName) const
|
|
||||||
{
|
|
||||||
std::deque<Id> nameIds = m_dictionary.getWordIdsConst(fullName, DELIMITER);
|
|
||||||
|
|
||||||
if (nameIds.size())
|
|
||||||
{
|
|
||||||
return m_root.getNodeRecursive(&nameIds).get();
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchIndex::SearchResults SearchIndex::runFuzzySearch(const std::string& query) const
|
|
||||||
{
|
|
||||||
return m_root.runFuzzySearch(query, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<SearchIndex::SearchMatch> SearchIndex::runFuzzySearchAndGetMatches(const std::string& query) const
|
|
||||||
{
|
|
||||||
return getMatches(runFuzzySearch(query), query);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string SearchIndex::DELIMITER = "::";
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
#ifndef SEARCH_INDEX_H
|
|
||||||
#define SEARCH_INDEX_H
|
|
||||||
|
|
||||||
#include <deque>
|
|
||||||
#include <map>
|
|
||||||
#include <memory>
|
|
||||||
#include <ostream>
|
|
||||||
#include <set>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "utility/text/Dictionary.h"
|
|
||||||
#include "utility/types.h"
|
|
||||||
|
|
||||||
class SearchIndex
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
class SearchNode;
|
|
||||||
|
|
||||||
struct SearchResult
|
|
||||||
{
|
|
||||||
SearchResult();
|
|
||||||
SearchResult(size_t weight, const SearchIndex::SearchNode* node, const SearchIndex::SearchNode* parent);
|
|
||||||
|
|
||||||
bool operator()(const SearchResult& lhs, const SearchResult& rhs) const;
|
|
||||||
|
|
||||||
size_t weight;
|
|
||||||
const SearchIndex::SearchNode* node;
|
|
||||||
const SearchIndex::SearchNode* parent;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::set<SearchResult, SearchResult> SearchResults;
|
|
||||||
typedef SearchResults::const_iterator SearchResultsIterator;
|
|
||||||
|
|
||||||
struct SearchMatch
|
|
||||||
{
|
|
||||||
void print(std::ostream& ostream) const;
|
|
||||||
|
|
||||||
std::string encodeForQuery() const;
|
|
||||||
|
|
||||||
std::string fullName;
|
|
||||||
std::set<Id> tokenIds;
|
|
||||||
std::vector<size_t> indices;
|
|
||||||
size_t weight;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SearchNode
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef std::multimap<size_t, const SearchIndex::SearchNode*> FuzzyMap;
|
|
||||||
typedef FuzzyMap::const_iterator FuzzyMapIterator;
|
|
||||||
|
|
||||||
SearchNode(SearchNode* parent, const std::string& name, Id nameId);
|
|
||||||
~SearchNode();
|
|
||||||
|
|
||||||
const std::string& getName() const;
|
|
||||||
std::string getFullName() const;
|
|
||||||
|
|
||||||
Id getNameId() const;
|
|
||||||
|
|
||||||
Id getFirstTokenId() const;
|
|
||||||
const std::set<Id>& getTokenIds() const;
|
|
||||||
void addTokenId(Id tokenId);
|
|
||||||
|
|
||||||
SearchNode* getParent() const;
|
|
||||||
std::deque<SearchIndex::SearchNode*> getParentsWithoutTokenId();
|
|
||||||
|
|
||||||
const std::set<std::shared_ptr<SearchNode>>& getChildren() const;
|
|
||||||
|
|
||||||
SearchResults runFuzzySearch(const std::string& query, bool recursive) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Accessed by SearchIndex
|
|
||||||
std::shared_ptr<SearchNode> addNodeRecursive(std::deque<Id>* nameIds, const Dictionary& dictionary);
|
|
||||||
std::shared_ptr<SearchNode> getNodeRecursive(std::deque<Id>* nameIds) const;
|
|
||||||
|
|
||||||
friend class SearchIndex;
|
|
||||||
|
|
||||||
FuzzyMap fuzzyMatchRecursive(const std::string& query, size_t pos, size_t weight, size_t size) const;
|
|
||||||
std::pair<size_t, size_t> fuzzyMatch(
|
|
||||||
const std::string query, size_t start, size_t size, std::vector<size_t>* indices = nullptr) const;
|
|
||||||
SearchMatch fuzzyMatchData(const std::string& query, const SearchNode* parent) const;
|
|
||||||
|
|
||||||
std::shared_ptr<SearchIndex::SearchNode> getChildWithNameId(Id nameId) const;
|
|
||||||
std::deque<const SearchNode*> getNodesToParent(const SearchNode* parent) const;
|
|
||||||
|
|
||||||
std::set<std::shared_ptr<SearchNode>> m_nodes;
|
|
||||||
SearchNode* m_parent;
|
|
||||||
|
|
||||||
std::set<Id> m_tokenIds;
|
|
||||||
|
|
||||||
const std::string& m_name;
|
|
||||||
const Id m_nameId;
|
|
||||||
};
|
|
||||||
|
|
||||||
static std::vector<SearchMatch> getMatches(const SearchResults& searchResults, const std::string& query);
|
|
||||||
|
|
||||||
static void logMatches(const std::vector<SearchMatch>& matches, const std::string& query);
|
|
||||||
|
|
||||||
SearchIndex();
|
|
||||||
virtual ~SearchIndex();
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
Id getWordId(const std::string& word);
|
|
||||||
const std::string& getWord(Id wordId) const;
|
|
||||||
|
|
||||||
SearchNode* addNode(std::vector<std::string> nameHierarchy);
|
|
||||||
SearchNode* getNode(const std::string& fullName) const;
|
|
||||||
|
|
||||||
SearchResults runFuzzySearch(const std::string& query) const;
|
|
||||||
std::vector<SearchMatch> runFuzzySearchAndGetMatches(const std::string& query) const;
|
|
||||||
|
|
||||||
static const std::string DELIMITER;
|
|
||||||
|
|
||||||
private:
|
|
||||||
SearchNode m_root;
|
|
||||||
Dictionary m_dictionary;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // SEARCH_INDEX_H
|
|
||||||
+15
-15
@@ -325,7 +325,7 @@ Id Storage::onTypeUsageParsed(const ParseTypeUsage& type, const ParseFunction& f
|
|||||||
|
|
||||||
Id Storage::getIdForNodeWithName(const std::string& fullName) const
|
Id Storage::getIdForNodeWithName(const std::string& fullName) const
|
||||||
{
|
{
|
||||||
SearchIndex::SearchNode* node = m_tokenIndex.getNode(fullName);
|
SearchNode* node = m_tokenIndex.getNode(fullName);
|
||||||
if (node)
|
if (node)
|
||||||
{
|
{
|
||||||
return node->getFirstTokenId();
|
return node->getFirstTokenId();
|
||||||
@@ -352,10 +352,10 @@ std::string Storage::getNameForNodeWithId(Id id) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<SearchIndex::SearchMatch> Storage::getAutocompletionMatches(
|
std::vector<SearchMatch> Storage::getAutocompletionMatches(
|
||||||
const std::string& query, const std::string& word) const
|
const std::string& query, const std::string& word) const
|
||||||
{
|
{
|
||||||
SearchIndex::SearchResults tokenResults;
|
SearchResults tokenResults;
|
||||||
|
|
||||||
bool usedSubquery = false;
|
bool usedSubquery = false;
|
||||||
if (query.size())
|
if (query.size())
|
||||||
@@ -370,12 +370,12 @@ std::vector<SearchIndex::SearchMatch> Storage::getAutocompletionMatches(
|
|||||||
|
|
||||||
if (word.size())
|
if (word.size())
|
||||||
{
|
{
|
||||||
SearchIndex::SearchResults filterResults = m_filterIndex.runFuzzySearch(word);
|
SearchResults filterResults = m_filterIndex.runFuzzySearch(word);
|
||||||
tokenResults.insert(filterResults.begin(), filterResults.end());
|
tokenResults.insert(filterResults.begin(), filterResults.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<SearchIndex::SearchMatch> matches = SearchIndex::getMatches(tokenResults, word);
|
std::vector<SearchMatch> matches = SearchIndex::getMatches(tokenResults, word);
|
||||||
SearchIndex::logMatches(matches, word);
|
SearchMatch::log(matches, word);
|
||||||
return matches;
|
return matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -588,7 +588,7 @@ const SearchIndex& Storage::getSearchIndex() const
|
|||||||
|
|
||||||
Node* Storage::addNodeHierarchy(Node::NodeType type, std::vector<std::string> nameHierarchy)
|
Node* Storage::addNodeHierarchy(Node::NodeType type, std::vector<std::string> nameHierarchy)
|
||||||
{
|
{
|
||||||
SearchIndex::SearchNode* searchNode = m_tokenIndex.addNode(nameHierarchy);
|
SearchNode* searchNode = m_tokenIndex.addNode(nameHierarchy);
|
||||||
if (!searchNode)
|
if (!searchNode)
|
||||||
{
|
{
|
||||||
LOG_ERROR("No SearchNode");
|
LOG_ERROR("No SearchNode");
|
||||||
@@ -600,7 +600,7 @@ Node* Storage::addNodeHierarchy(Node::NodeType type, std::vector<std::string> na
|
|||||||
|
|
||||||
Node* Storage::addNodeHierarchyWithDistinctSignature(Node::NodeType type, const ParseFunction& function)
|
Node* Storage::addNodeHierarchyWithDistinctSignature(Node::NodeType type, const ParseFunction& function)
|
||||||
{
|
{
|
||||||
SearchIndex::SearchNode* searchNode = m_tokenIndex.addNode(function.nameHierarchy);
|
SearchNode* searchNode = m_tokenIndex.addNode(function.nameHierarchy);
|
||||||
if (!searchNode)
|
if (!searchNode)
|
||||||
{
|
{
|
||||||
LOG_ERROR("No SearchNode");
|
LOG_ERROR("No SearchNode");
|
||||||
@@ -728,7 +728,7 @@ TokenLocation* Storage::addTokenLocation(Token* token, const ParseLocation& loc,
|
|||||||
bool Storage::getSubQuerySearchResults(
|
bool Storage::getSubQuerySearchResults(
|
||||||
const std::string& query,
|
const std::string& query,
|
||||||
const std::string& word,
|
const std::string& word,
|
||||||
SearchIndex::SearchResults* results
|
SearchResults* results
|
||||||
) const {
|
) const {
|
||||||
std::string q = query;
|
std::string q = query;
|
||||||
bool returnChilds = false;
|
bool returnChilds = false;
|
||||||
@@ -757,7 +757,7 @@ bool Storage::getSubQuerySearchResults(
|
|||||||
GraphFilterConductor conductor;
|
GraphFilterConductor conductor;
|
||||||
conductor.filter(&tree, &m_graph, &graph);
|
conductor.filter(&tree, &m_graph, &graph);
|
||||||
|
|
||||||
std::vector<const SearchIndex::SearchNode*> searchNodes;
|
std::vector<const SearchNode*> searchNodes;
|
||||||
graph.forEachNode(
|
graph.forEachNode(
|
||||||
[&searchNodes](Node* node)
|
[&searchNodes](Node* node)
|
||||||
{
|
{
|
||||||
@@ -769,23 +769,23 @@ bool Storage::getSubQuerySearchResults(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const SearchIndex::SearchNode* node : searchNodes)
|
for (const SearchNode* node : searchNodes)
|
||||||
{
|
{
|
||||||
if (word.size())
|
if (word.size())
|
||||||
{
|
{
|
||||||
SearchIndex::SearchResults res = node->runFuzzySearch(word, returnChilds);
|
SearchResults res = node->runFuzzySearch(word, returnChilds);
|
||||||
results->insert(res.begin(), res.end());
|
results->insert(res.begin(), res.end());
|
||||||
}
|
}
|
||||||
else if (returnChilds)
|
else if (returnChilds)
|
||||||
{
|
{
|
||||||
for (const std::shared_ptr<SearchIndex::SearchNode>& child : node->getChildren())
|
for (const std::shared_ptr<SearchNode>& child : node->getChildren())
|
||||||
{
|
{
|
||||||
results->insert(SearchIndex::SearchResult(0, child.get(), child.get()));
|
results->insert(SearchResult(0, child.get(), child.get()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (searchNodes.size() > 1)
|
else if (searchNodes.size() > 1)
|
||||||
{
|
{
|
||||||
results->insert(SearchIndex::SearchResult(0, node, node));
|
results->insert(SearchResult(0, node, node));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
#include "data/graph/token_component/TokenComponentAccess.h"
|
#include "data/graph/token_component/TokenComponentAccess.h"
|
||||||
#include "data/location/TokenLocationCollection.h"
|
#include "data/location/TokenLocationCollection.h"
|
||||||
#include "data/parser/ParserClient.h"
|
#include "data/parser/ParserClient.h"
|
||||||
#include "data/SearchIndex.h"
|
#include "data/search/SearchIndex.h"
|
||||||
|
|
||||||
class Storage
|
class Storage
|
||||||
: public ParserClient
|
: public ParserClient
|
||||||
@@ -71,7 +71,7 @@ public:
|
|||||||
// GraphAccess implementation
|
// GraphAccess implementation
|
||||||
virtual Id getIdForNodeWithName(const std::string& fullName) const;
|
virtual Id getIdForNodeWithName(const std::string& fullName) const;
|
||||||
virtual std::string getNameForNodeWithId(Id id) const;
|
virtual std::string getNameForNodeWithId(Id id) const;
|
||||||
virtual std::vector<SearchIndex::SearchMatch> getAutocompletionMatches(
|
virtual std::vector<SearchMatch> getAutocompletionMatches(
|
||||||
const std::string& query, const std::string& word) const;
|
const std::string& query, const std::string& word) const;
|
||||||
|
|
||||||
virtual std::shared_ptr<Graph> getGraphForActiveTokenIds(const std::vector<Id>& tokenIds) const;
|
virtual std::shared_ptr<Graph> getGraphForActiveTokenIds(const std::vector<Id>& tokenIds) const;
|
||||||
@@ -110,7 +110,7 @@ private:
|
|||||||
TokenLocation* addTokenLocation(Token* token, const ParseLocation& location, bool isScope = false);
|
TokenLocation* addTokenLocation(Token* token, const ParseLocation& location, bool isScope = false);
|
||||||
|
|
||||||
bool getSubQuerySearchResults(
|
bool getSubQuerySearchResults(
|
||||||
const std::string& query, const std::string& word, SearchIndex::SearchResults* results) const;
|
const std::string& query, const std::string& word, SearchResults* results) const;
|
||||||
|
|
||||||
void log(std::string type, std::string str, const ParseLocation& location) const;
|
void log(std::string type, std::string str, const ParseLocation& location) const;
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "data/graph/Graph.h"
|
#include "data/graph/Graph.h"
|
||||||
#include "data/SearchIndex.h"
|
#include "data/search/SearchMatch.h"
|
||||||
#include "utility/types.h"
|
#include "utility/types.h"
|
||||||
|
|
||||||
class GraphAccess
|
class GraphAccess
|
||||||
@@ -16,7 +16,7 @@ public:
|
|||||||
|
|
||||||
virtual Id getIdForNodeWithName(const std::string& name) const = 0;
|
virtual Id getIdForNodeWithName(const std::string& name) const = 0;
|
||||||
virtual std::string getNameForNodeWithId(Id id) const = 0;
|
virtual std::string getNameForNodeWithId(Id id) const = 0;
|
||||||
virtual std::vector<SearchIndex::SearchMatch> getAutocompletionMatches(
|
virtual std::vector<SearchMatch> getAutocompletionMatches(
|
||||||
const std::string& query, const std::string& word) const = 0;
|
const std::string& query, const std::string& word) const = 0;
|
||||||
|
|
||||||
virtual std::shared_ptr<Graph> getGraphForActiveTokenIds(const std::vector<Id>& tokenIds) const = 0;
|
virtual std::shared_ptr<Graph> getGraphForActiveTokenIds(const std::vector<Id>& tokenIds) const = 0;
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ std::string GraphAccessProxy::getNameForNodeWithId(Id id) const
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<SearchIndex::SearchMatch> GraphAccessProxy::getAutocompletionMatches(
|
std::vector<SearchMatch> GraphAccessProxy::getAutocompletionMatches(
|
||||||
const std::string& query,
|
const std::string& query,
|
||||||
const std::string& word
|
const std::string& word
|
||||||
) const {
|
) const {
|
||||||
@@ -56,7 +56,7 @@ std::vector<SearchIndex::SearchMatch> GraphAccessProxy::getAutocompletionMatches
|
|||||||
return m_subject->getAutocompletionMatches(query, word);
|
return m_subject->getAutocompletionMatches(query, word);
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::vector<SearchIndex::SearchMatch>();
|
return std::vector<SearchMatch>();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Graph> GraphAccessProxy::getGraphForActiveTokenIds(const std::vector<Id>& tokenIds) const
|
std::shared_ptr<Graph> GraphAccessProxy::getGraphForActiveTokenIds(const std::vector<Id>& tokenIds) const
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public:
|
|||||||
// GraphAccess implementation
|
// GraphAccess implementation
|
||||||
virtual Id getIdForNodeWithName(const std::string& name) const;
|
virtual Id getIdForNodeWithName(const std::string& name) const;
|
||||||
virtual std::string getNameForNodeWithId(Id id) const;
|
virtual std::string getNameForNodeWithId(Id id) const;
|
||||||
virtual std::vector<SearchIndex::SearchMatch> getAutocompletionMatches(
|
virtual std::vector<SearchMatch> getAutocompletionMatches(
|
||||||
const std::string& query, const std::string& word) const;
|
const std::string& query, const std::string& word) const;
|
||||||
|
|
||||||
virtual std::shared_ptr<Graph> getGraphForActiveTokenIds(const std::vector<Id>& tokenIds) const;
|
virtual std::shared_ptr<Graph> getGraphForActiveTokenIds(const std::vector<Id>& tokenIds) const;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ StorageGraph::~StorageGraph()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Node* StorageGraph::createNodeHierarchy(Node::NodeType type, SearchIndex::SearchNode* searchNode)
|
Node* StorageGraph::createNodeHierarchy(Node::NodeType type, SearchNode* searchNode)
|
||||||
{
|
{
|
||||||
Node* node = getNodeById(searchNode->getFirstTokenId());
|
Node* node = getNodeById(searchNode->getFirstTokenId());
|
||||||
if (!node)
|
if (!node)
|
||||||
@@ -29,7 +29,7 @@ Node* StorageGraph::createNodeHierarchy(Node::NodeType type, SearchIndex::Search
|
|||||||
}
|
}
|
||||||
|
|
||||||
Node* StorageGraph::createNodeHierarchyWithDistinctSignature(
|
Node* StorageGraph::createNodeHierarchyWithDistinctSignature(
|
||||||
Node::NodeType type, SearchIndex::SearchNode* searchNode, std::shared_ptr<TokenComponentSignature> signature
|
Node::NodeType type, SearchNode* searchNode, std::shared_ptr<TokenComponentSignature> signature
|
||||||
){
|
){
|
||||||
Node* node = getNodeById(searchNode->getFirstTokenId());
|
Node* node = getNodeById(searchNode->getFirstTokenId());
|
||||||
if (!node)
|
if (!node)
|
||||||
@@ -90,9 +90,9 @@ Edge* StorageGraph::createEdge(Edge::EdgeType type, Node* from, Node* to)
|
|||||||
return insertEdge(type, from, to);
|
return insertEdge(type, from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
Node* StorageGraph::insertNodeHierarchy(Node::NodeType type, SearchIndex::SearchNode* searchNode)
|
Node* StorageGraph::insertNodeHierarchy(Node::NodeType type, SearchNode* searchNode)
|
||||||
{
|
{
|
||||||
std::deque<SearchIndex::SearchNode*> searchNodes = searchNode->getParentsWithoutTokenId();
|
std::deque<SearchNode*> searchNodes = searchNode->getParentsWithoutTokenId();
|
||||||
|
|
||||||
if (!searchNodes.size())
|
if (!searchNodes.size())
|
||||||
{
|
{
|
||||||
@@ -101,7 +101,7 @@ Node* StorageGraph::insertNodeHierarchy(Node::NodeType type, SearchIndex::Search
|
|||||||
}
|
}
|
||||||
|
|
||||||
Node* parentNode = nullptr;
|
Node* parentNode = nullptr;
|
||||||
SearchIndex::SearchNode* parentSearchNode = searchNodes.front()->getParent();
|
SearchNode* parentSearchNode = searchNodes.front()->getParent();
|
||||||
if (parentSearchNode)
|
if (parentSearchNode)
|
||||||
{
|
{
|
||||||
parentNode = getNodeById(parentSearchNode->getFirstTokenId());
|
parentNode = getNodeById(parentSearchNode->getFirstTokenId());
|
||||||
@@ -118,7 +118,7 @@ Node* StorageGraph::insertNodeHierarchy(Node::NodeType type, SearchIndex::Search
|
|||||||
return parentNode;
|
return parentNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node* StorageGraph::insertNode(Node::NodeType type, Node* parentNode, SearchIndex::SearchNode* searchNode)
|
Node* StorageGraph::insertNode(Node::NodeType type, Node* parentNode, SearchNode* searchNode)
|
||||||
{
|
{
|
||||||
std::shared_ptr<Node> node =
|
std::shared_ptr<Node> node =
|
||||||
std::make_shared<Node>(type, std::make_shared<TokenComponentNameReferenced>(searchNode));
|
std::make_shared<Node>(type, std::make_shared<TokenComponentNameReferenced>(searchNode));
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "data/graph/Graph.h"
|
#include "data/graph/Graph.h"
|
||||||
#include "data/graph/token_component/TokenComponentSignature.h"
|
#include "data/graph/token_component/TokenComponentSignature.h"
|
||||||
#include "data/SearchIndex.h"
|
#include "data/search/SearchNode.h"
|
||||||
|
|
||||||
class StorageGraph
|
class StorageGraph
|
||||||
: public Graph
|
: public Graph
|
||||||
@@ -12,14 +12,14 @@ public:
|
|||||||
StorageGraph();
|
StorageGraph();
|
||||||
virtual ~StorageGraph();
|
virtual ~StorageGraph();
|
||||||
|
|
||||||
Node* createNodeHierarchy(Node::NodeType type, SearchIndex::SearchNode* searchNode);
|
Node* createNodeHierarchy(Node::NodeType type, SearchNode* searchNode);
|
||||||
Node* createNodeHierarchyWithDistinctSignature(
|
Node* createNodeHierarchyWithDistinctSignature(
|
||||||
Node::NodeType type, SearchIndex::SearchNode* searchNode, std::shared_ptr<TokenComponentSignature> signature);
|
Node::NodeType type, SearchNode* searchNode, std::shared_ptr<TokenComponentSignature> signature);
|
||||||
Edge* createEdge(Edge::EdgeType type, Node* from, Node* to);
|
Edge* createEdge(Edge::EdgeType type, Node* from, Node* to);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Node* insertNodeHierarchy(Node::NodeType type, SearchIndex::SearchNode* searchNode);
|
Node* insertNodeHierarchy(Node::NodeType type, SearchNode* searchNode);
|
||||||
Node* insertNode(Node::NodeType type, Node* parentNode, SearchIndex::SearchNode* searchNode);
|
Node* insertNode(Node::NodeType type, Node* parentNode, SearchNode* searchNode);
|
||||||
Edge* insertEdge(Edge::EdgeType type, Node* from, Node* to);
|
Edge* insertEdge(Edge::EdgeType type, Node* from, Node* to);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include "utility/utilityString.h"
|
#include "utility/utilityString.h"
|
||||||
|
|
||||||
|
#include "data/search/SearchIndex.h"
|
||||||
|
|
||||||
TokenComponentName::TokenComponentName()
|
TokenComponentName::TokenComponentName()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -16,7 +18,7 @@ std::shared_ptr<TokenComponentName> TokenComponentName::copyComponentName() cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TokenComponentNameReferenced::TokenComponentNameReferenced(const SearchIndex::SearchNode* searchNode)
|
TokenComponentNameReferenced::TokenComponentNameReferenced(const SearchNode* searchNode)
|
||||||
: m_searchNode(searchNode)
|
: m_searchNode(searchNode)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -40,7 +42,7 @@ std::string TokenComponentNameReferenced::getFullName() const
|
|||||||
return m_searchNode->getFullName();
|
return m_searchNode->getFullName();
|
||||||
}
|
}
|
||||||
|
|
||||||
const SearchIndex::SearchNode* TokenComponentNameReferenced::getSearchNode() const
|
const SearchNode* TokenComponentNameReferenced::getSearchNode() const
|
||||||
{
|
{
|
||||||
return m_searchNode;
|
return m_searchNode;
|
||||||
}
|
}
|
||||||
@@ -69,7 +71,7 @@ std::string TokenComponentNameCached::getFullName() const
|
|||||||
return m_fullName;
|
return m_fullName;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SearchIndex::SearchNode* TokenComponentNameCached::getSearchNode() const
|
const SearchNode* TokenComponentNameCached::getSearchNode() const
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "data/graph/token_component/TokenComponent.h"
|
#include "data/graph/token_component/TokenComponent.h"
|
||||||
#include "data/SearchIndex.h"
|
#include "data/search/SearchNode.h"
|
||||||
|
|
||||||
class TokenComponentName
|
class TokenComponentName
|
||||||
: public TokenComponent
|
: public TokenComponent
|
||||||
@@ -18,7 +18,7 @@ public:
|
|||||||
virtual std::string getName() const = 0;
|
virtual std::string getName() const = 0;
|
||||||
virtual std::string getFullName() const = 0;
|
virtual std::string getFullName() const = 0;
|
||||||
|
|
||||||
virtual const SearchIndex::SearchNode* getSearchNode() const = 0;
|
virtual const SearchNode* getSearchNode() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ class TokenComponentNameReferenced
|
|||||||
: public TokenComponentName
|
: public TokenComponentName
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TokenComponentNameReferenced(const SearchIndex::SearchNode* searchNode);
|
TokenComponentNameReferenced(const SearchNode* searchNode);
|
||||||
virtual ~TokenComponentNameReferenced();
|
virtual ~TokenComponentNameReferenced();
|
||||||
|
|
||||||
virtual std::shared_ptr<TokenComponent> copy() const;
|
virtual std::shared_ptr<TokenComponent> copy() const;
|
||||||
@@ -34,10 +34,10 @@ public:
|
|||||||
virtual std::string getName() const;
|
virtual std::string getName() const;
|
||||||
virtual std::string getFullName() const;
|
virtual std::string getFullName() const;
|
||||||
|
|
||||||
virtual const SearchIndex::SearchNode* getSearchNode() const;
|
virtual const SearchNode* getSearchNode() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const SearchIndex::SearchNode* m_searchNode;
|
const SearchNode* m_searchNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ public:
|
|||||||
virtual std::string getName() const;
|
virtual std::string getName() const;
|
||||||
virtual std::string getFullName() const;
|
virtual std::string getFullName() const;
|
||||||
|
|
||||||
virtual const SearchIndex::SearchNode* getSearchNode() const;
|
virtual const SearchNode* getSearchNode() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::string m_fullName;
|
const std::string m_fullName;
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
#include "data/search/SearchIndex.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
|
|
||||||
|
#include "data/search/SearchMatch.h"
|
||||||
|
|
||||||
|
std::vector<SearchMatch> SearchIndex::getMatches(
|
||||||
|
const SearchResults& searchResults,
|
||||||
|
const std::string& query
|
||||||
|
){
|
||||||
|
std::vector<SearchMatch> result;
|
||||||
|
|
||||||
|
for (SearchResultsIterator it = searchResults.begin(); it != searchResults.end(); it++)
|
||||||
|
{
|
||||||
|
SearchMatch match = it->node->fuzzyMatchData(query, it->parent);
|
||||||
|
result.push_back(match);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchIndex::SearchIndex()
|
||||||
|
: m_root(nullptr, DELIMITER, 0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchIndex::~SearchIndex()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchIndex::clear()
|
||||||
|
{
|
||||||
|
m_root.m_nodes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
Id SearchIndex::getWordId(const std::string& word)
|
||||||
|
{
|
||||||
|
return m_dictionary.getWordId(word);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& SearchIndex::getWord(Id wordId) const
|
||||||
|
{
|
||||||
|
return m_dictionary.getWord(wordId);
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchNode* SearchIndex::addNode(std::vector<std::string> nameHierarchy)
|
||||||
|
{
|
||||||
|
std::deque<Id> nameIds;
|
||||||
|
for (const std::string& name: nameHierarchy)
|
||||||
|
{
|
||||||
|
nameIds.push_back(m_dictionary.getWordId(name));
|
||||||
|
}
|
||||||
|
if (nameIds.size())
|
||||||
|
{
|
||||||
|
return m_root.addNodeRecursive(&nameIds, m_dictionary).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchNode* SearchIndex::getNode(const std::string& fullName) const
|
||||||
|
{
|
||||||
|
std::deque<Id> nameIds = m_dictionary.getWordIdsConst(fullName, DELIMITER);
|
||||||
|
|
||||||
|
if (nameIds.size())
|
||||||
|
{
|
||||||
|
return m_root.getNodeRecursive(&nameIds).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchResults SearchIndex::runFuzzySearch(const std::string& query) const
|
||||||
|
{
|
||||||
|
return m_root.runFuzzySearch(query, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<SearchMatch> SearchIndex::runFuzzySearchAndGetMatches(const std::string& query) const
|
||||||
|
{
|
||||||
|
return getMatches(runFuzzySearch(query), query);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string SearchIndex::DELIMITER = "::";
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#ifndef SEARCH_INDEX_H
|
||||||
|
#define SEARCH_INDEX_H
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
#include <set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "utility/text/Dictionary.h"
|
||||||
|
#include "utility/types.h"
|
||||||
|
|
||||||
|
#include "data/search/SearchNode.h"
|
||||||
|
|
||||||
|
class SearchIndex
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::vector<SearchMatch> getMatches(const SearchResults& searchResults, const std::string& query);
|
||||||
|
|
||||||
|
SearchIndex();
|
||||||
|
virtual ~SearchIndex();
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
Id getWordId(const std::string& word);
|
||||||
|
const std::string& getWord(Id wordId) const;
|
||||||
|
|
||||||
|
SearchNode* addNode(std::vector<std::string> nameHierarchy);
|
||||||
|
SearchNode* getNode(const std::string& fullName) const;
|
||||||
|
|
||||||
|
SearchResults runFuzzySearch(const std::string& query) const;
|
||||||
|
std::vector<SearchMatch> runFuzzySearchAndGetMatches(const std::string& query) const;
|
||||||
|
|
||||||
|
static const std::string DELIMITER;
|
||||||
|
|
||||||
|
private:
|
||||||
|
SearchNode m_root;
|
||||||
|
Dictionary m_dictionary;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SEARCH_INDEX_H
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
#include "data/search/SearchMatch.h"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "utility/logging/logging.h"
|
||||||
|
|
||||||
|
#include "data/query/QueryCommand.h"
|
||||||
|
#include "data/query/QueryToken.h"
|
||||||
|
|
||||||
|
void SearchMatch::log(const std::vector<SearchMatch>& matches, const std::string& query)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << std::endl << matches.size() << " matches for \"" << query << "\":" << std::endl;
|
||||||
|
|
||||||
|
for (const SearchMatch& match : matches)
|
||||||
|
{
|
||||||
|
match.print(ss);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO(ss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchMatch::print(std::ostream& ostream) const
|
||||||
|
{
|
||||||
|
ostream << weight << '\t' << fullName << std::endl << '\t';
|
||||||
|
size_t i = 0;
|
||||||
|
for (size_t index : indices)
|
||||||
|
{
|
||||||
|
while (i < index)
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
ostream << ' ';
|
||||||
|
}
|
||||||
|
ostream << '^';
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
ostream << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SearchMatch::encodeForQuery() const
|
||||||
|
{
|
||||||
|
if (!tokenIds.size())
|
||||||
|
{
|
||||||
|
return QueryCommand::BOUNDARY + fullName + QueryCommand::BOUNDARY;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << QueryToken::BOUNDARY << fullName;
|
||||||
|
for (Id tokenId : tokenIds)
|
||||||
|
{
|
||||||
|
ss << QueryToken::DELIMITER << tokenId;
|
||||||
|
}
|
||||||
|
ss << QueryToken::BOUNDARY;
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef SEARCH_MATCH_H
|
||||||
|
#define SEARCH_MATCH_H
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "utility/types.h"
|
||||||
|
|
||||||
|
struct SearchMatch
|
||||||
|
{
|
||||||
|
static void log(const std::vector<SearchMatch>& matches, const std::string& query);
|
||||||
|
void print(std::ostream& ostream) const;
|
||||||
|
|
||||||
|
std::string encodeForQuery() const;
|
||||||
|
|
||||||
|
std::string fullName;
|
||||||
|
std::set<Id> tokenIds;
|
||||||
|
std::vector<size_t> indices;
|
||||||
|
size_t weight;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SEARCH_MATCH_H
|
||||||
@@ -0,0 +1,309 @@
|
|||||||
|
#include "data/search/SearchNode.h"
|
||||||
|
|
||||||
|
#include "utility/text/Dictionary.h"
|
||||||
|
|
||||||
|
#include "data/search/SearchIndex.h"
|
||||||
|
#include "data/search/SearchMatch.h"
|
||||||
|
#include "data/search/SearchResult.h"
|
||||||
|
|
||||||
|
SearchNode::SearchNode(SearchNode* parent, const std::string& name, Id nameId)
|
||||||
|
: m_parent(parent)
|
||||||
|
, m_name(name)
|
||||||
|
, m_nameId(nameId)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchNode::~SearchNode()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& SearchNode::getName() const
|
||||||
|
{
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SearchNode::getFullName() const
|
||||||
|
{
|
||||||
|
if (m_parent && m_parent->m_nameId)
|
||||||
|
{
|
||||||
|
return m_parent->getFullName() + SearchIndex::DELIMITER + getName();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Id SearchNode::getNameId() const
|
||||||
|
{
|
||||||
|
return m_nameId;
|
||||||
|
}
|
||||||
|
|
||||||
|
Id SearchNode::getFirstTokenId() const
|
||||||
|
{
|
||||||
|
if (m_tokenIds.size())
|
||||||
|
{
|
||||||
|
return *m_tokenIds.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::set<Id>& SearchNode::getTokenIds() const
|
||||||
|
{
|
||||||
|
return m_tokenIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchNode::addTokenId(Id tokenId)
|
||||||
|
{
|
||||||
|
m_tokenIds.insert(tokenId);
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchNode* SearchNode::getParent() const
|
||||||
|
{
|
||||||
|
if (m_parent && m_parent->m_nameId)
|
||||||
|
{
|
||||||
|
return m_parent;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::deque<SearchNode*> SearchNode::getParentsWithoutTokenId()
|
||||||
|
{
|
||||||
|
std::deque<SearchNode*> nodes;
|
||||||
|
|
||||||
|
SearchNode* node = this;
|
||||||
|
while (node->m_nameId && !node->m_tokenIds.size())
|
||||||
|
{
|
||||||
|
nodes.push_front(node);
|
||||||
|
node = node->m_parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::set<std::shared_ptr<SearchNode>>& SearchNode::getChildren() const
|
||||||
|
{
|
||||||
|
return m_nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchResults SearchNode::runFuzzySearch(const std::string& query, bool recursive) const
|
||||||
|
{
|
||||||
|
SearchResults result;
|
||||||
|
|
||||||
|
if (recursive)
|
||||||
|
{
|
||||||
|
for (std::shared_ptr<SearchNode> n: m_nodes)
|
||||||
|
{
|
||||||
|
FuzzyMap m = n->fuzzyMatchRecursive(query, 0, 0, 0);
|
||||||
|
for (const std::pair<size_t, const SearchNode*>& p : m)
|
||||||
|
{
|
||||||
|
result.insert(SearchResult(p.first, p.second, this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::pair<size_t, size_t> p = fuzzyMatch(query, 0, 0);
|
||||||
|
size_t pos = p.first;
|
||||||
|
size_t weight = p.second;
|
||||||
|
|
||||||
|
if (pos == query.size())
|
||||||
|
{
|
||||||
|
result.insert(SearchResult(weight, this, this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Currently all matches are added to the ordered set and get compared by their fullName for alphabetical
|
||||||
|
// order. This could be improved by limiting the number of items to e.g. 100.
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SearchNode> SearchNode::addNodeRecursive(
|
||||||
|
std::deque<Id>* nameIds, const Dictionary& dictionary
|
||||||
|
){
|
||||||
|
Id nameId = nameIds->front();
|
||||||
|
nameIds->pop_front();
|
||||||
|
|
||||||
|
std::shared_ptr<SearchNode> node = getChildWithNameId(nameId);
|
||||||
|
if (!node)
|
||||||
|
{
|
||||||
|
node = std::make_shared<SearchNode>(this, dictionary.getWord(nameId), nameId);
|
||||||
|
m_nodes.insert(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nameIds->size() > 0)
|
||||||
|
{
|
||||||
|
return node->addNodeRecursive(nameIds, dictionary);
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SearchNode> SearchNode::getNodeRecursive(std::deque<Id>* nameIds) const
|
||||||
|
{
|
||||||
|
Id nameId = nameIds->front();
|
||||||
|
nameIds->pop_front();
|
||||||
|
|
||||||
|
std::shared_ptr<SearchNode> node = getChildWithNameId(nameId);
|
||||||
|
if (node)
|
||||||
|
{
|
||||||
|
if (!nameIds->size())
|
||||||
|
{
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node->getNodeRecursive(nameIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchMatch SearchNode::fuzzyMatchData(const std::string& query, const SearchNode* parent) const
|
||||||
|
{
|
||||||
|
SearchMatch data;
|
||||||
|
data.fullName = getFullName();
|
||||||
|
data.tokenIds = m_tokenIds;
|
||||||
|
data.weight = 0;
|
||||||
|
|
||||||
|
size_t pos = 0;
|
||||||
|
size_t size = 0;
|
||||||
|
|
||||||
|
std::deque<const SearchNode*> nodes = getNodesToParent(parent);
|
||||||
|
if (!nodes.size())
|
||||||
|
{
|
||||||
|
nodes.push_back(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const SearchNode* node : nodes)
|
||||||
|
{
|
||||||
|
std::pair<size_t, size_t> p = node->fuzzyMatch(query, pos, size, &data.indices);
|
||||||
|
pos = p.first;
|
||||||
|
data.weight += p.second;
|
||||||
|
size += node->m_name.size() + SearchIndex::DELIMITER.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchNode::FuzzyMap SearchNode::fuzzyMatchRecursive(
|
||||||
|
const std::string& query, size_t pos, size_t weight, size_t size) const
|
||||||
|
{
|
||||||
|
FuzzyMap result;
|
||||||
|
std::pair<size_t, size_t> p = fuzzyMatch(query, pos, size);
|
||||||
|
pos = p.first;
|
||||||
|
weight += p.second;
|
||||||
|
|
||||||
|
if (pos == query.size())
|
||||||
|
{
|
||||||
|
result.emplace(weight, this);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::shared_ptr<SearchNode> n: m_nodes)
|
||||||
|
{
|
||||||
|
FuzzyMap m = n->fuzzyMatchRecursive(query, pos, weight, size + m_name.size() + SearchIndex::DELIMITER.size());
|
||||||
|
result.insert(m.begin(), m.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<size_t, size_t> SearchNode::fuzzyMatch(
|
||||||
|
const std::string query, size_t start, size_t size, std::vector<size_t>* indices) const
|
||||||
|
{
|
||||||
|
size_t pos = start;
|
||||||
|
size_t weight = 0;
|
||||||
|
size_t matchCount = 0;
|
||||||
|
char lastChar = '\0';
|
||||||
|
|
||||||
|
size_t ql = query.size();
|
||||||
|
size_t ml = m_name.size();
|
||||||
|
|
||||||
|
if (!query.size())
|
||||||
|
{
|
||||||
|
return std::pair<size_t, size_t>(pos, weight);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query[pos] == ':')
|
||||||
|
{
|
||||||
|
pos++;
|
||||||
|
if (indices && size >= 2)
|
||||||
|
{
|
||||||
|
indices->push_back(size - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos < ql && query[pos] == ':')
|
||||||
|
{
|
||||||
|
pos++;
|
||||||
|
if (indices && size >= 1)
|
||||||
|
{
|
||||||
|
indices->push_back(size - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < ml; i++)
|
||||||
|
{
|
||||||
|
char c = m_name[i];
|
||||||
|
if (tolower(query[pos]) == tolower(c))
|
||||||
|
{
|
||||||
|
weight += std::max<size_t>(100 - size - i, 1);
|
||||||
|
if (matchCount)
|
||||||
|
{
|
||||||
|
weight += matchCount * 10;
|
||||||
|
}
|
||||||
|
else if (i == 0 || lastChar == '_' || tolower(c) != c)
|
||||||
|
{
|
||||||
|
weight += 20;
|
||||||
|
}
|
||||||
|
matchCount++;
|
||||||
|
|
||||||
|
pos++;
|
||||||
|
if (indices)
|
||||||
|
{
|
||||||
|
indices->push_back(size + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos == ql || query[pos] == ':')
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
matchCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastChar = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::pair<size_t, size_t>(pos, weight);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SearchNode> SearchNode::getChildWithNameId(Id nameId) const
|
||||||
|
{
|
||||||
|
for (std::shared_ptr<SearchNode> n: m_nodes)
|
||||||
|
{
|
||||||
|
if (n->m_nameId == nameId)
|
||||||
|
{
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::deque<const SearchNode*> SearchNode::getNodesToParent(const SearchNode* parent) const
|
||||||
|
{
|
||||||
|
std::deque<const SearchNode*> nodes;
|
||||||
|
|
||||||
|
const SearchNode* node = this;
|
||||||
|
while (node->m_nameId && node != parent)
|
||||||
|
{
|
||||||
|
nodes.push_front(node);
|
||||||
|
node = node->m_parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
#ifndef SEARCH_NODE_H
|
||||||
|
#define SEARCH_NODE_H
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "utility/types.h"
|
||||||
|
|
||||||
|
#include "data/search/SearchResult.h"
|
||||||
|
|
||||||
|
class Dictionary;
|
||||||
|
class SearchIndex;
|
||||||
|
struct SearchMatch;
|
||||||
|
|
||||||
|
class SearchNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SearchNode(SearchNode* parent, const std::string& name, Id nameId);
|
||||||
|
~SearchNode();
|
||||||
|
|
||||||
|
const std::string& getName() const;
|
||||||
|
std::string getFullName() const;
|
||||||
|
|
||||||
|
Id getNameId() const;
|
||||||
|
|
||||||
|
Id getFirstTokenId() const;
|
||||||
|
const std::set<Id>& getTokenIds() const;
|
||||||
|
void addTokenId(Id tokenId);
|
||||||
|
|
||||||
|
SearchNode* getParent() const;
|
||||||
|
std::deque<SearchNode*> getParentsWithoutTokenId();
|
||||||
|
|
||||||
|
const std::set<std::shared_ptr<SearchNode>>& getChildren() const;
|
||||||
|
|
||||||
|
SearchResults runFuzzySearch(const std::string& query, bool recursive) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef std::multimap<size_t, const SearchNode*> FuzzyMap;
|
||||||
|
typedef FuzzyMap::const_iterator FuzzyMapIterator;
|
||||||
|
|
||||||
|
// Accessed by SearchIndex
|
||||||
|
std::shared_ptr<SearchNode> addNodeRecursive(std::deque<Id>* nameIds, const Dictionary& dictionary);
|
||||||
|
std::shared_ptr<SearchNode> getNodeRecursive(std::deque<Id>* nameIds) const;
|
||||||
|
|
||||||
|
SearchMatch fuzzyMatchData(const std::string& query, const SearchNode* parent) const;
|
||||||
|
|
||||||
|
friend class SearchIndex;
|
||||||
|
|
||||||
|
FuzzyMap fuzzyMatchRecursive(const std::string& query, size_t pos, size_t weight, size_t size) const;
|
||||||
|
std::pair<size_t, size_t> fuzzyMatch(
|
||||||
|
const std::string query, size_t start, size_t size, std::vector<size_t>* indices = nullptr) const;
|
||||||
|
|
||||||
|
std::shared_ptr<SearchNode> getChildWithNameId(Id nameId) const;
|
||||||
|
std::deque<const SearchNode*> getNodesToParent(const SearchNode* parent) const;
|
||||||
|
|
||||||
|
std::set<std::shared_ptr<SearchNode>> m_nodes;
|
||||||
|
SearchNode* m_parent;
|
||||||
|
|
||||||
|
std::set<Id> m_tokenIds;
|
||||||
|
|
||||||
|
const std::string& m_name;
|
||||||
|
const Id m_nameId;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SEARCH_NODE_H
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#include "data/search/SearchResult.h"
|
||||||
|
|
||||||
|
#include "data/search/SearchNode.h"
|
||||||
|
|
||||||
|
SearchResult::SearchResult()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchResult::SearchResult(size_t weight, const SearchNode* node, const SearchNode* parent)
|
||||||
|
: weight(weight)
|
||||||
|
, node(node)
|
||||||
|
, parent(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SearchResult::operator()(const SearchResult& lhs, const SearchResult& rhs) const
|
||||||
|
{
|
||||||
|
if (lhs.weight != rhs.weight)
|
||||||
|
{
|
||||||
|
return lhs.weight > rhs.weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lhs.node->getFullName() < rhs.node->getFullName();
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#ifndef SEARCH_RESULT_H
|
||||||
|
#define SEARCH_RESULT_H
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
class SearchNode;
|
||||||
|
|
||||||
|
struct SearchResult
|
||||||
|
{
|
||||||
|
SearchResult();
|
||||||
|
SearchResult(size_t weight, const SearchNode* node, const SearchNode* parent);
|
||||||
|
|
||||||
|
bool operator()(const SearchResult& lhs, const SearchResult& rhs) const;
|
||||||
|
|
||||||
|
size_t weight;
|
||||||
|
const SearchNode* node;
|
||||||
|
const SearchNode* parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::set<SearchResult, SearchResult> SearchResults;
|
||||||
|
typedef SearchResults::const_iterator SearchResultsIterator;
|
||||||
|
|
||||||
|
#endif // SEARCH_RESULT_H
|
||||||
@@ -165,7 +165,7 @@ private:
|
|||||||
{
|
{
|
||||||
createTestStorage();
|
createTestStorage();
|
||||||
|
|
||||||
std::vector<SearchIndex::SearchMatch> matches = m_storage->getAutocompletionMatches("", name);
|
std::vector<SearchMatch> matches = m_storage->getAutocompletionMatches("", name);
|
||||||
if (matches.size() && matches[0].fullName == name)
|
if (matches.size() && matches[0].fullName == name)
|
||||||
{
|
{
|
||||||
return matches[0].tokenIds;
|
return matches[0].tokenIds;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "cxxtest/TestSuite.h"
|
#include "cxxtest/TestSuite.h"
|
||||||
|
|
||||||
#include "data/SearchIndex.h"
|
#include "data/search/SearchIndex.h"
|
||||||
#include "utility/utilityString.h"
|
#include "utility/utilityString.h"
|
||||||
|
|
||||||
class SearchIndexTestSuite : public CxxTest::TestSuite
|
class SearchIndexTestSuite : public CxxTest::TestSuite
|
||||||
@@ -9,7 +9,7 @@ public:
|
|||||||
void test_add_node()
|
void test_add_node()
|
||||||
{
|
{
|
||||||
SearchIndex index;
|
SearchIndex index;
|
||||||
SearchIndex::SearchNode* node = index.addNode(utility::splitToVector("util", "::"));
|
SearchNode* node = index.addNode(utility::splitToVector("util", "::"));
|
||||||
|
|
||||||
TS_ASSERT(node);
|
TS_ASSERT(node);
|
||||||
TS_ASSERT_EQUALS("util", node->getName());
|
TS_ASSERT_EQUALS("util", node->getName());
|
||||||
@@ -24,7 +24,7 @@ public:
|
|||||||
{
|
{
|
||||||
SearchIndex index;
|
SearchIndex index;
|
||||||
index.addNode(utility::splitToVector("util", "::"));
|
index.addNode(utility::splitToVector("util", "::"));
|
||||||
SearchIndex::SearchNode* node = index.getNode("util");
|
SearchNode* node = index.getNode("util");
|
||||||
|
|
||||||
TS_ASSERT(node);
|
TS_ASSERT(node);
|
||||||
TS_ASSERT_EQUALS("util", node->getName());
|
TS_ASSERT_EQUALS("util", node->getName());
|
||||||
@@ -41,7 +41,7 @@ public:
|
|||||||
void test_add_hierarchy_node()
|
void test_add_hierarchy_node()
|
||||||
{
|
{
|
||||||
SearchIndex index;
|
SearchIndex index;
|
||||||
SearchIndex::SearchNode* node = index.addNode(utility::splitToVector("util::math::pow", "::"));
|
SearchNode* node = index.addNode(utility::splitToVector("util::math::pow", "::"));
|
||||||
|
|
||||||
TS_ASSERT(node);
|
TS_ASSERT(node);
|
||||||
TS_ASSERT_EQUALS("pow", node->getName());
|
TS_ASSERT_EQUALS("pow", node->getName());
|
||||||
@@ -60,8 +60,8 @@ public:
|
|||||||
void test_reuse_hierarchy_node()
|
void test_reuse_hierarchy_node()
|
||||||
{
|
{
|
||||||
SearchIndex index;
|
SearchIndex index;
|
||||||
SearchIndex::SearchNode* node1 = index.addNode(utility::splitToVector("math::pow", "::"));
|
SearchNode* node1 = index.addNode(utility::splitToVector("math::pow", "::"));
|
||||||
SearchIndex::SearchNode* node2 = index.addNode(utility::splitToVector("math::floor", "::"));
|
SearchNode* node2 = index.addNode(utility::splitToVector("math::floor", "::"));
|
||||||
|
|
||||||
TS_ASSERT(node1);
|
TS_ASSERT(node1);
|
||||||
TS_ASSERT(node2);
|
TS_ASSERT(node2);
|
||||||
@@ -92,7 +92,7 @@ public:
|
|||||||
index.addNode(utility::splitToVector("math", "::"));
|
index.addNode(utility::splitToVector("math", "::"));
|
||||||
index.addNode(utility::splitToVector("string", "::"));
|
index.addNode(utility::splitToVector("string", "::"));
|
||||||
|
|
||||||
std::vector<SearchIndex::SearchMatch> matches = index.runFuzzySearchAndGetMatches("u");
|
std::vector<SearchMatch> matches = index.runFuzzySearchAndGetMatches("u");
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(1, matches.size());
|
TS_ASSERT_EQUALS(1, matches.size());
|
||||||
TS_ASSERT_EQUALS("util", matches[0].fullName);
|
TS_ASSERT_EQUALS("util", matches[0].fullName);
|
||||||
@@ -117,7 +117,7 @@ public:
|
|||||||
index.addNode(utility::splitToVector("util", "::"));
|
index.addNode(utility::splitToVector("util", "::"));
|
||||||
index.addNode(utility::splitToVector("MATH", "::"));
|
index.addNode(utility::splitToVector("MATH", "::"));
|
||||||
|
|
||||||
std::vector<SearchIndex::SearchMatch> matches = index.runFuzzySearchAndGetMatches("t");
|
std::vector<SearchMatch> matches = index.runFuzzySearchAndGetMatches("t");
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(2, matches.size());
|
TS_ASSERT_EQUALS(2, matches.size());
|
||||||
TS_ASSERT_EQUALS("MATH", matches[0].fullName);
|
TS_ASSERT_EQUALS("MATH", matches[0].fullName);
|
||||||
@@ -137,7 +137,7 @@ public:
|
|||||||
index.addNode(utility::splitToVector("math", "::"));
|
index.addNode(utility::splitToVector("math", "::"));
|
||||||
index.addNode(utility::splitToVector("string", "::"));
|
index.addNode(utility::splitToVector("string", "::"));
|
||||||
|
|
||||||
std::vector<SearchIndex::SearchMatch> matches = index.runFuzzySearchAndGetMatches("t");
|
std::vector<SearchMatch> matches = index.runFuzzySearchAndGetMatches("t");
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(3, matches.size());
|
TS_ASSERT_EQUALS(3, matches.size());
|
||||||
TS_ASSERT_EQUALS("string", matches[0].fullName);
|
TS_ASSERT_EQUALS("string", matches[0].fullName);
|
||||||
@@ -160,7 +160,7 @@ public:
|
|||||||
index.addNode(utility::splitToVector("uTil", "::"));
|
index.addNode(utility::splitToVector("uTil", "::"));
|
||||||
index.addNode(utility::splitToVector("string", "::"));
|
index.addNode(utility::splitToVector("string", "::"));
|
||||||
|
|
||||||
std::vector<SearchIndex::SearchMatch> matches = index.runFuzzySearchAndGetMatches("t");
|
std::vector<SearchMatch> matches = index.runFuzzySearchAndGetMatches("t");
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(2, matches.size());
|
TS_ASSERT_EQUALS(2, matches.size());
|
||||||
TS_ASSERT_EQUALS("uTil", matches[0].fullName);
|
TS_ASSERT_EQUALS("uTil", matches[0].fullName);
|
||||||
@@ -173,7 +173,7 @@ public:
|
|||||||
index.addNode(utility::splitToVector("oaabbcc", "::"));
|
index.addNode(utility::splitToVector("oaabbcc", "::"));
|
||||||
index.addNode(utility::splitToVector("ocbaabc", "::"));
|
index.addNode(utility::splitToVector("ocbaabc", "::"));
|
||||||
|
|
||||||
std::vector<SearchIndex::SearchMatch> matches = index.runFuzzySearchAndGetMatches("abc");
|
std::vector<SearchMatch> matches = index.runFuzzySearchAndGetMatches("abc");
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(2, matches.size());
|
TS_ASSERT_EQUALS(2, matches.size());
|
||||||
TS_ASSERT_EQUALS("ocbaabc", matches[0].fullName);
|
TS_ASSERT_EQUALS("ocbaabc", matches[0].fullName);
|
||||||
@@ -187,7 +187,7 @@ public:
|
|||||||
index.addNode(utility::splitToVector("util::math::floor", "::"));
|
index.addNode(utility::splitToVector("util::math::floor", "::"));
|
||||||
index.addNode(utility::splitToVector("util::string::concat", "::"));
|
index.addNode(utility::splitToVector("util::string::concat", "::"));
|
||||||
|
|
||||||
std::vector<SearchIndex::SearchMatch> matches = index.runFuzzySearchAndGetMatches("t");
|
std::vector<SearchMatch> matches = index.runFuzzySearchAndGetMatches("t");
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(1, matches.size());
|
TS_ASSERT_EQUALS(1, matches.size());
|
||||||
TS_ASSERT_EQUALS("util", matches[0].fullName);
|
TS_ASSERT_EQUALS("util", matches[0].fullName);
|
||||||
@@ -206,7 +206,7 @@ public:
|
|||||||
index.addNode(utility::splitToVector("util::math::floor", "::"));
|
index.addNode(utility::splitToVector("util::math::floor", "::"));
|
||||||
index.addNode(utility::splitToVector("util::string::concat", "::"));
|
index.addNode(utility::splitToVector("util::string::concat", "::"));
|
||||||
|
|
||||||
std::vector<SearchIndex::SearchMatch> matches = index.runFuzzySearchAndGetMatches("u:i");
|
std::vector<SearchMatch> matches = index.runFuzzySearchAndGetMatches("u:i");
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(2, matches.size());
|
TS_ASSERT_EQUALS(2, matches.size());
|
||||||
TS_ASSERT_EQUALS("util::string", matches[0].fullName);
|
TS_ASSERT_EQUALS("util::string", matches[0].fullName);
|
||||||
@@ -224,7 +224,7 @@ public:
|
|||||||
index.addNode(utility::splitToVector("abc::dfe::ghi", "::"));
|
index.addNode(utility::splitToVector("abc::dfe::ghi", "::"));
|
||||||
index.addNode(utility::splitToVector("abc::hgi", "::"));
|
index.addNode(utility::splitToVector("abc::hgi", "::"));
|
||||||
|
|
||||||
std::vector<SearchIndex::SearchMatch> matches = index.runFuzzySearchAndGetMatches("g");
|
std::vector<SearchMatch> matches = index.runFuzzySearchAndGetMatches("g");
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(2, matches.size());
|
TS_ASSERT_EQUALS(2, matches.size());
|
||||||
TS_ASSERT_EQUALS("abc::dfe::ghi", matches[0].fullName);
|
TS_ASSERT_EQUALS("abc::dfe::ghi", matches[0].fullName);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "cxxtest/TestSuite.h"
|
#include "cxxtest/TestSuite.h"
|
||||||
|
|
||||||
#include "data/graph/StorageGraph.h"
|
#include "data/graph/StorageGraph.h"
|
||||||
#include "data/SearchIndex.h"
|
#include "data/search/SearchIndex.h"
|
||||||
|
|
||||||
class StorageGraphTestSuite : public CxxTest::TestSuite
|
class StorageGraphTestSuite : public CxxTest::TestSuite
|
||||||
{
|
{
|
||||||
@@ -295,14 +295,14 @@ private:
|
|||||||
public:
|
public:
|
||||||
Node* createNodeHierarchy(Node::NodeType type, const std::string& name)
|
Node* createNodeHierarchy(Node::NodeType type, const std::string& name)
|
||||||
{
|
{
|
||||||
SearchIndex::SearchNode* searchNode = m_index.addNode(utility::splitToVector(name, "::"));
|
SearchNode* searchNode = m_index.addNode(utility::splitToVector(name, "::"));
|
||||||
return StorageGraph::createNodeHierarchy(type, searchNode);
|
return StorageGraph::createNodeHierarchy(type, searchNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
Node* createNodeHierarchyWithDistinctSignature(
|
Node* createNodeHierarchyWithDistinctSignature(
|
||||||
Node::NodeType type, const std::string& name, Id signatureId
|
Node::NodeType type, const std::string& name, Id signatureId
|
||||||
){
|
){
|
||||||
SearchIndex::SearchNode* searchNode = m_index.addNode(utility::splitToVector(name, "::"));
|
SearchNode* searchNode = m_index.addNode(utility::splitToVector(name, "::"));
|
||||||
std::shared_ptr<TokenComponentSignature> signature = std::make_shared<TokenComponentSignature>(signatureId);
|
std::shared_ptr<TokenComponentSignature> signature = std::make_shared<TokenComponentSignature>(signatureId);
|
||||||
return StorageGraph::createNodeHierarchyWithDistinctSignature(type, searchNode, signature);
|
return StorageGraph::createNodeHierarchyWithDistinctSignature(type, searchNode, signature);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user