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: call: main -> B::B <input.cc 36:4 36:4>
|
||||
Storage.cpp INFO: call: main -> A::getCount <input.cc 38:9 38:21>
|
||||
SearchIndex.cpp INFO:
|
||||
SearchMatch.cpp INFO:
|
||||
1 matches for "main":
|
||||
474 main
|
||||
^^^^
|
||||
|
||||
SearchIndex.cpp INFO:
|
||||
SearchMatch.cpp INFO:
|
||||
1 matches for "main":
|
||||
474 main
|
||||
^^^^
|
||||
|
||||
SearchIndex.cpp INFO:
|
||||
SearchMatch.cpp INFO:
|
||||
1 matches for "A::A":
|
||||
237 A::A
|
||||
^^^^
|
||||
|
||||
@@ -49,7 +49,7 @@ void QtSearchBar::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);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <QAbstractItemView>
|
||||
#include <QFrame>
|
||||
|
||||
#include "data/SearchIndex.h"
|
||||
#include "data/search/SearchMatch.h"
|
||||
|
||||
class QPushButton;
|
||||
class QtSmartSearchBox;
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
|
||||
void setText(const std::string& text);
|
||||
void setFocus();
|
||||
void setAutocompletionList(const std::vector<SearchIndex::SearchMatch>& autocompletionList);
|
||||
void setAutocompletionList(const std::vector<SearchMatch>& autocompletionList);
|
||||
|
||||
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;
|
||||
|
||||
@@ -63,7 +63,7 @@ void QtSmartSearchBox::setAutocompletionList(const std::vector<SearchIndex::Sear
|
||||
}
|
||||
|
||||
QStringList wordList;
|
||||
for (const SearchIndex::SearchMatch& match: autocompletionList)
|
||||
for (const SearchMatch& match: autocompletionList)
|
||||
{
|
||||
wordList << match.fullName.c_str();
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
#ifndef QT_SMART_SEARCH_BOX_H
|
||||
#define QT_SMART_SEARCH_BOX_H
|
||||
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
|
||||
#include "data/SearchIndex.h"
|
||||
#include "data/search/SearchMatch.h"
|
||||
|
||||
class QtQueryElement
|
||||
: public QPushButton
|
||||
@@ -37,7 +38,7 @@ public:
|
||||
QtSmartSearchBox(QWidget* parent);
|
||||
virtual ~QtSmartSearchBox();
|
||||
|
||||
void setAutocompletionList(const std::vector<SearchIndex::SearchMatch>& autocompletionList);
|
||||
void setAutocompletionList(const std::vector<SearchMatch>& autocompletionList);
|
||||
void setQuery(const std::string& text);
|
||||
void setFocus();
|
||||
|
||||
@@ -90,7 +91,7 @@ private:
|
||||
|
||||
size_t m_cursorIndex;
|
||||
|
||||
std::vector<SearchIndex::SearchMatch> m_matches;
|
||||
std::vector<SearchMatch> m_matches;
|
||||
|
||||
bool m_shiftKeyDown;
|
||||
bool m_mousePressed;
|
||||
|
||||
@@ -43,7 +43,7 @@ void QtSearchView::setFocus()
|
||||
m_setFocusFunctor();
|
||||
}
|
||||
|
||||
void QtSearchView::setAutocompletionList(const std::vector<SearchIndex::SearchMatch>& autocompletionList)
|
||||
void QtSearchView::setAutocompletionList(const std::vector<SearchMatch>& autocompletionList)
|
||||
{
|
||||
m_setAutocompletionListFunctor(autocompletionList);
|
||||
}
|
||||
@@ -64,7 +64,7 @@ void QtSearchView::doSetFocus()
|
||||
m_widget->setFocus();
|
||||
}
|
||||
|
||||
void QtSearchView::doSetAutocompletionList(const std::vector<SearchIndex::SearchMatch>& autocompletionList)
|
||||
void QtSearchView::doSetAutocompletionList(const std::vector<SearchMatch>& autocompletionList)
|
||||
{
|
||||
m_widget->setAutocompletionList(autocompletionList);
|
||||
setStyleSheet();
|
||||
|
||||
@@ -21,20 +21,20 @@ public:
|
||||
// SearchView implementation
|
||||
virtual void setText(const std::string& text);
|
||||
virtual void setFocus();
|
||||
virtual void setAutocompletionList(const std::vector<SearchIndex::SearchMatch>& autocompletionList);
|
||||
virtual void setAutocompletionList(const std::vector<SearchMatch>& autocompletionList);
|
||||
|
||||
private:
|
||||
void doRefreshView();
|
||||
void doSetText(const std::string& text);
|
||||
void doSetFocus();
|
||||
void doSetAutocompletionList(const std::vector<SearchIndex::SearchMatch>& autocompletionList);
|
||||
void doSetAutocompletionList(const std::vector<SearchMatch>& autocompletionList);
|
||||
|
||||
void setStyleSheet();
|
||||
|
||||
QtThreadedFunctor<> m_refreshViewFunctor;
|
||||
QtThreadedFunctor<const std::string&> m_setTextFunctor;
|
||||
QtThreadedFunctor<> m_setFocusFunctor;
|
||||
QtThreadedFunctor<const std::vector<SearchIndex::SearchMatch>&> m_setAutocompletionListFunctor;
|
||||
QtThreadedFunctor<const std::vector<SearchMatch>&> m_setAutocompletionListFunctor;
|
||||
|
||||
std::shared_ptr<QtSearchBar> m_widget;
|
||||
};
|
||||
|
||||
@@ -142,6 +142,15 @@ add_files(
|
||||
data/query/QueryTree.cpp
|
||||
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.h
|
||||
data/type/modifier/DataTypeModifierArray.cpp
|
||||
@@ -158,8 +167,6 @@ add_files(
|
||||
data/type/DataTypeQualifierList.cpp
|
||||
data/type/DataTypeQualifierList.h
|
||||
|
||||
data/SearchIndex.cpp
|
||||
data/SearchIndex.h
|
||||
data/Storage.cpp
|
||||
data/Storage.h
|
||||
|
||||
|
||||
@@ -18,10 +18,11 @@ void SearchController::handleMessage(MessageActivateToken* message)
|
||||
{
|
||||
if (!m_ignoreNextMessageActivateToken && message->tokenId)
|
||||
{
|
||||
std::string name = m_graphAccess->getNameForNodeWithId(message->tokenId);
|
||||
std::stringstream ss;
|
||||
ss << '"' << name << ',' << message->tokenId << '"';
|
||||
getView()->setText(ss.str());
|
||||
SearchMatch match;
|
||||
match.fullName = m_graphAccess->getNameForNodeWithId(message->tokenId);
|
||||
match.tokenIds.insert(message->tokenId);
|
||||
|
||||
getView()->setText(match.encodeForQuery());
|
||||
}
|
||||
|
||||
m_ignoreNextMessageActivateToken = false;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define SEARCH_VIEW_H
|
||||
|
||||
#include "component/view/View.h"
|
||||
#include "data/SearchIndex.h"
|
||||
#include "data/search/SearchMatch.h"
|
||||
|
||||
class SearchController;
|
||||
|
||||
@@ -16,7 +16,7 @@ public:
|
||||
|
||||
virtual void setText(const std::string& s) = 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:
|
||||
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
|
||||
{
|
||||
SearchIndex::SearchNode* node = m_tokenIndex.getNode(fullName);
|
||||
SearchNode* node = m_tokenIndex.getNode(fullName);
|
||||
if (node)
|
||||
{
|
||||
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
|
||||
{
|
||||
SearchIndex::SearchResults tokenResults;
|
||||
SearchResults tokenResults;
|
||||
|
||||
bool usedSubquery = false;
|
||||
if (query.size())
|
||||
@@ -370,12 +370,12 @@ std::vector<SearchIndex::SearchMatch> Storage::getAutocompletionMatches(
|
||||
|
||||
if (word.size())
|
||||
{
|
||||
SearchIndex::SearchResults filterResults = m_filterIndex.runFuzzySearch(word);
|
||||
SearchResults filterResults = m_filterIndex.runFuzzySearch(word);
|
||||
tokenResults.insert(filterResults.begin(), filterResults.end());
|
||||
}
|
||||
|
||||
std::vector<SearchIndex::SearchMatch> matches = SearchIndex::getMatches(tokenResults, word);
|
||||
SearchIndex::logMatches(matches, word);
|
||||
std::vector<SearchMatch> matches = SearchIndex::getMatches(tokenResults, word);
|
||||
SearchMatch::log(matches, word);
|
||||
return matches;
|
||||
}
|
||||
|
||||
@@ -588,7 +588,7 @@ const SearchIndex& Storage::getSearchIndex() const
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
SearchIndex::SearchNode* searchNode = m_tokenIndex.addNode(function.nameHierarchy);
|
||||
SearchNode* searchNode = m_tokenIndex.addNode(function.nameHierarchy);
|
||||
if (!searchNode)
|
||||
{
|
||||
LOG_ERROR("No SearchNode");
|
||||
@@ -728,7 +728,7 @@ TokenLocation* Storage::addTokenLocation(Token* token, const ParseLocation& loc,
|
||||
bool Storage::getSubQuerySearchResults(
|
||||
const std::string& query,
|
||||
const std::string& word,
|
||||
SearchIndex::SearchResults* results
|
||||
SearchResults* results
|
||||
) const {
|
||||
std::string q = query;
|
||||
bool returnChilds = false;
|
||||
@@ -757,7 +757,7 @@ bool Storage::getSubQuerySearchResults(
|
||||
GraphFilterConductor conductor;
|
||||
conductor.filter(&tree, &m_graph, &graph);
|
||||
|
||||
std::vector<const SearchIndex::SearchNode*> searchNodes;
|
||||
std::vector<const SearchNode*> searchNodes;
|
||||
graph.forEachNode(
|
||||
[&searchNodes](Node* node)
|
||||
{
|
||||
@@ -769,23 +769,23 @@ bool Storage::getSubQuerySearchResults(
|
||||
}
|
||||
);
|
||||
|
||||
for (const SearchIndex::SearchNode* node : searchNodes)
|
||||
for (const SearchNode* node : searchNodes)
|
||||
{
|
||||
if (word.size())
|
||||
{
|
||||
SearchIndex::SearchResults res = node->runFuzzySearch(word, returnChilds);
|
||||
SearchResults res = node->runFuzzySearch(word, returnChilds);
|
||||
results->insert(res.begin(), res.end());
|
||||
}
|
||||
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)
|
||||
{
|
||||
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/location/TokenLocationCollection.h"
|
||||
#include "data/parser/ParserClient.h"
|
||||
#include "data/SearchIndex.h"
|
||||
#include "data/search/SearchIndex.h"
|
||||
|
||||
class Storage
|
||||
: public ParserClient
|
||||
@@ -71,7 +71,7 @@ public:
|
||||
// GraphAccess implementation
|
||||
virtual Id getIdForNodeWithName(const std::string& fullName) 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;
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "data/graph/Graph.h"
|
||||
#include "data/SearchIndex.h"
|
||||
#include "data/search/SearchMatch.h"
|
||||
#include "utility/types.h"
|
||||
|
||||
class GraphAccess
|
||||
@@ -16,7 +16,7 @@ public:
|
||||
|
||||
virtual Id getIdForNodeWithName(const std::string& name) 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;
|
||||
|
||||
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 "";
|
||||
}
|
||||
|
||||
std::vector<SearchIndex::SearchMatch> GraphAccessProxy::getAutocompletionMatches(
|
||||
std::vector<SearchMatch> GraphAccessProxy::getAutocompletionMatches(
|
||||
const std::string& query,
|
||||
const std::string& word
|
||||
) const {
|
||||
@@ -56,7 +56,7 @@ std::vector<SearchIndex::SearchMatch> GraphAccessProxy::getAutocompletionMatches
|
||||
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
|
||||
|
||||
@@ -15,7 +15,7 @@ public:
|
||||
// GraphAccess implementation
|
||||
virtual Id getIdForNodeWithName(const std::string& name) 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;
|
||||
|
||||
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());
|
||||
if (!node)
|
||||
@@ -29,7 +29,7 @@ Node* StorageGraph::createNodeHierarchy(Node::NodeType type, SearchIndex::Search
|
||||
}
|
||||
|
||||
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());
|
||||
if (!node)
|
||||
@@ -90,9 +90,9 @@ Edge* StorageGraph::createEdge(Edge::EdgeType type, Node* from, Node* 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())
|
||||
{
|
||||
@@ -101,7 +101,7 @@ Node* StorageGraph::insertNodeHierarchy(Node::NodeType type, SearchIndex::Search
|
||||
}
|
||||
|
||||
Node* parentNode = nullptr;
|
||||
SearchIndex::SearchNode* parentSearchNode = searchNodes.front()->getParent();
|
||||
SearchNode* parentSearchNode = searchNodes.front()->getParent();
|
||||
if (parentSearchNode)
|
||||
{
|
||||
parentNode = getNodeById(parentSearchNode->getFirstTokenId());
|
||||
@@ -118,7 +118,7 @@ Node* StorageGraph::insertNodeHierarchy(Node::NodeType type, SearchIndex::Search
|
||||
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::make_shared<Node>(type, std::make_shared<TokenComponentNameReferenced>(searchNode));
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include "data/graph/Graph.h"
|
||||
#include "data/graph/token_component/TokenComponentSignature.h"
|
||||
#include "data/SearchIndex.h"
|
||||
#include "data/search/SearchNode.h"
|
||||
|
||||
class StorageGraph
|
||||
: public Graph
|
||||
@@ -12,14 +12,14 @@ public:
|
||||
StorageGraph();
|
||||
virtual ~StorageGraph();
|
||||
|
||||
Node* createNodeHierarchy(Node::NodeType type, SearchIndex::SearchNode* searchNode);
|
||||
Node* createNodeHierarchy(Node::NodeType type, SearchNode* searchNode);
|
||||
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);
|
||||
|
||||
private:
|
||||
Node* insertNodeHierarchy(Node::NodeType type, SearchIndex::SearchNode* searchNode);
|
||||
Node* insertNode(Node::NodeType type, Node* parentNode, SearchIndex::SearchNode* searchNode);
|
||||
Node* insertNodeHierarchy(Node::NodeType type, SearchNode* searchNode);
|
||||
Node* insertNode(Node::NodeType type, Node* parentNode, SearchNode* searchNode);
|
||||
Edge* insertEdge(Edge::EdgeType type, Node* from, Node* to);
|
||||
};
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include "utility/utilityString.h"
|
||||
|
||||
#include "data/search/SearchIndex.h"
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
@@ -40,7 +42,7 @@ std::string TokenComponentNameReferenced::getFullName() const
|
||||
return m_searchNode->getFullName();
|
||||
}
|
||||
|
||||
const SearchIndex::SearchNode* TokenComponentNameReferenced::getSearchNode() const
|
||||
const SearchNode* TokenComponentNameReferenced::getSearchNode() const
|
||||
{
|
||||
return m_searchNode;
|
||||
}
|
||||
@@ -69,7 +71,7 @@ std::string TokenComponentNameCached::getFullName() const
|
||||
return m_fullName;
|
||||
}
|
||||
|
||||
const SearchIndex::SearchNode* TokenComponentNameCached::getSearchNode() const
|
||||
const SearchNode* TokenComponentNameCached::getSearchNode() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "data/graph/token_component/TokenComponent.h"
|
||||
#include "data/SearchIndex.h"
|
||||
#include "data/search/SearchNode.h"
|
||||
|
||||
class TokenComponentName
|
||||
: public TokenComponent
|
||||
@@ -18,7 +18,7 @@ public:
|
||||
virtual std::string getName() 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:
|
||||
TokenComponentNameReferenced(const SearchIndex::SearchNode* searchNode);
|
||||
TokenComponentNameReferenced(const SearchNode* searchNode);
|
||||
virtual ~TokenComponentNameReferenced();
|
||||
|
||||
virtual std::shared_ptr<TokenComponent> copy() const;
|
||||
@@ -34,10 +34,10 @@ public:
|
||||
virtual std::string getName() const;
|
||||
virtual std::string getFullName() const;
|
||||
|
||||
virtual const SearchIndex::SearchNode* getSearchNode() const;
|
||||
virtual const SearchNode* getSearchNode() const;
|
||||
|
||||
private:
|
||||
const SearchIndex::SearchNode* m_searchNode;
|
||||
const SearchNode* m_searchNode;
|
||||
};
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
virtual std::string getName() const;
|
||||
virtual std::string getFullName() const;
|
||||
|
||||
virtual const SearchIndex::SearchNode* getSearchNode() const;
|
||||
virtual const SearchNode* getSearchNode() const;
|
||||
|
||||
private:
|
||||
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();
|
||||
|
||||
std::vector<SearchIndex::SearchMatch> matches = m_storage->getAutocompletionMatches("", name);
|
||||
std::vector<SearchMatch> matches = m_storage->getAutocompletionMatches("", name);
|
||||
if (matches.size() && matches[0].fullName == name)
|
||||
{
|
||||
return matches[0].tokenIds;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "cxxtest/TestSuite.h"
|
||||
|
||||
#include "data/SearchIndex.h"
|
||||
#include "data/search/SearchIndex.h"
|
||||
#include "utility/utilityString.h"
|
||||
|
||||
class SearchIndexTestSuite : public CxxTest::TestSuite
|
||||
@@ -9,7 +9,7 @@ public:
|
||||
void test_add_node()
|
||||
{
|
||||
SearchIndex index;
|
||||
SearchIndex::SearchNode* node = index.addNode(utility::splitToVector("util", "::"));
|
||||
SearchNode* node = index.addNode(utility::splitToVector("util", "::"));
|
||||
|
||||
TS_ASSERT(node);
|
||||
TS_ASSERT_EQUALS("util", node->getName());
|
||||
@@ -24,7 +24,7 @@ public:
|
||||
{
|
||||
SearchIndex index;
|
||||
index.addNode(utility::splitToVector("util", "::"));
|
||||
SearchIndex::SearchNode* node = index.getNode("util");
|
||||
SearchNode* node = index.getNode("util");
|
||||
|
||||
TS_ASSERT(node);
|
||||
TS_ASSERT_EQUALS("util", node->getName());
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
void test_add_hierarchy_node()
|
||||
{
|
||||
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_EQUALS("pow", node->getName());
|
||||
@@ -60,8 +60,8 @@ public:
|
||||
void test_reuse_hierarchy_node()
|
||||
{
|
||||
SearchIndex index;
|
||||
SearchIndex::SearchNode* node1 = index.addNode(utility::splitToVector("math::pow", "::"));
|
||||
SearchIndex::SearchNode* node2 = index.addNode(utility::splitToVector("math::floor", "::"));
|
||||
SearchNode* node1 = index.addNode(utility::splitToVector("math::pow", "::"));
|
||||
SearchNode* node2 = index.addNode(utility::splitToVector("math::floor", "::"));
|
||||
|
||||
TS_ASSERT(node1);
|
||||
TS_ASSERT(node2);
|
||||
@@ -92,7 +92,7 @@ public:
|
||||
index.addNode(utility::splitToVector("math", "::"));
|
||||
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("util", matches[0].fullName);
|
||||
@@ -117,7 +117,7 @@ public:
|
||||
index.addNode(utility::splitToVector("util", "::"));
|
||||
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("MATH", matches[0].fullName);
|
||||
@@ -137,7 +137,7 @@ public:
|
||||
index.addNode(utility::splitToVector("math", "::"));
|
||||
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("string", matches[0].fullName);
|
||||
@@ -160,7 +160,7 @@ public:
|
||||
index.addNode(utility::splitToVector("uTil", "::"));
|
||||
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("uTil", matches[0].fullName);
|
||||
@@ -173,7 +173,7 @@ public:
|
||||
index.addNode(utility::splitToVector("oaabbcc", "::"));
|
||||
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("ocbaabc", matches[0].fullName);
|
||||
@@ -187,7 +187,7 @@ public:
|
||||
index.addNode(utility::splitToVector("util::math::floor", "::"));
|
||||
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("util", matches[0].fullName);
|
||||
@@ -206,7 +206,7 @@ public:
|
||||
index.addNode(utility::splitToVector("util::math::floor", "::"));
|
||||
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("util::string", matches[0].fullName);
|
||||
@@ -224,7 +224,7 @@ public:
|
||||
index.addNode(utility::splitToVector("abc::dfe::ghi", "::"));
|
||||
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("abc::dfe::ghi", matches[0].fullName);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "cxxtest/TestSuite.h"
|
||||
|
||||
#include "data/graph/StorageGraph.h"
|
||||
#include "data/SearchIndex.h"
|
||||
#include "data/search/SearchIndex.h"
|
||||
|
||||
class StorageGraphTestSuite : public CxxTest::TestSuite
|
||||
{
|
||||
@@ -295,14 +295,14 @@ private:
|
||||
public:
|
||||
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);
|
||||
}
|
||||
|
||||
Node* createNodeHierarchyWithDistinctSignature(
|
||||
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);
|
||||
return StorageGraph::createNodeHierarchyWithDistinctSignature(type, searchNode, signature);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user