logic: search ui performance optimization
* replaced the implementation of the search index. the search index now uses a search-trie. edges have gates that can be used to check if a character can be matched when following the edge. * SearchMatches now have a text and a list of NameHierarchies that share this node (instead of Ids, so that nodes must be found by names (which makes sure that SearchMatches are still valid after refresh). * when parsing a project's description the CodeController now looks for NameHierarchies instead of SearchNode names to find ids of linked elements.
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
LET'S GET STARTED!\n
|
||||
\tTo keep things simple just click the "main" symbol below to start the tour.\n
|
||||
\n
|
||||
[main](); // <- start here\n\n
|
||||
[main\tint\r()](); // <- start here\n\n
|
||||
</description>
|
||||
</info>
|
||||
<source>
|
||||
|
||||
@@ -1,171 +1,3 @@
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Settings.cpp WARNING: File for Settings not found: data/TestSettings.xml
|
||||
Token.cpp ERROR: Location Id was not referenced by this Token.
|
||||
Node.cpp WARNING: Cannot change NodeType after it was already set from namespace to class
|
||||
Edge.cpp ERROR: Nodes are not plain copies.
|
||||
|
||||
@@ -134,12 +134,8 @@ add_files(
|
||||
|
||||
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/ArrayModifiedDataType.cpp
|
||||
data/type/ArrayModifiedDataType.h
|
||||
|
||||
@@ -582,6 +582,7 @@ std::vector<std::string> CodeController::getProjectDescription(TokenLocationFile
|
||||
return std::vector<std::string>();
|
||||
}
|
||||
|
||||
// todo fixme: this split currently prevents the next step from recognizing multi level name hierarchies.
|
||||
std::vector<std::string> lines = utility::splitToVector(description, "\\n");
|
||||
size_t startLineNumber = 4;
|
||||
|
||||
@@ -590,6 +591,7 @@ std::vector<std::string> CodeController::getProjectDescription(TokenLocationFile
|
||||
std::string line = "\t" + lines[i];
|
||||
|
||||
line = utility::replace(line, "\\t", "\t");
|
||||
line = utility::replace(line, "\\r", "\r");
|
||||
|
||||
size_t pos = 0;
|
||||
while (pos != std::string::npos)
|
||||
@@ -602,21 +604,23 @@ std::vector<std::string> CodeController::getProjectDescription(TokenLocationFile
|
||||
break;
|
||||
}
|
||||
|
||||
std::string tokenName = line.substr(posA + 1, posB - posA - 1);
|
||||
std::string serializedName = line.substr(posA + 1, posB - posA - 1);
|
||||
|
||||
Id tokenId = m_storageAccess->getIdForNodeWithSearchNameHierarchy(NameHierarchy(tokenName));
|
||||
NameHierarchy nameHierarchy = NameHierarchy::deserialize(serializedName);
|
||||
Id tokenId = m_storageAccess->getIdForNodeWithNameHierarchy(nameHierarchy);
|
||||
|
||||
if (tokenId > 0)
|
||||
{
|
||||
line.replace(posA, posB - posA + 1, tokenName);
|
||||
std::string nameString = nameHierarchy.getQualifiedName();
|
||||
line.replace(posA, posB - posA + 1, nameString);
|
||||
locationFile->addTokenLocation(
|
||||
0, tokenId,
|
||||
startLineNumber + i, posA + 1,
|
||||
startLineNumber + i, posA + tokenName.size()
|
||||
startLineNumber + i, posA + nameString.size()
|
||||
);
|
||||
}
|
||||
|
||||
pos = posA + tokenName.size();
|
||||
pos = posA + serializedName.size();
|
||||
}
|
||||
|
||||
lines[i] = line;
|
||||
|
||||
+63
-74
@@ -39,8 +39,9 @@ Version Storage::getVersion() const
|
||||
|
||||
bool Storage::init()
|
||||
{
|
||||
m_commandIndex.addNode(NameHierarchy(SearchMatch::getCommandName(SearchMatch::COMMAND_ALL)));
|
||||
m_commandIndex.addNode(NameHierarchy(SearchMatch::getCommandName(SearchMatch::COMMAND_ERROR)));
|
||||
m_commandIndex.addNode(0, NameHierarchy(SearchMatch::getCommandName(SearchMatch::COMMAND_ALL)));
|
||||
m_commandIndex.addNode(0, NameHierarchy(SearchMatch::getCommandName(SearchMatch::COMMAND_ERROR)));
|
||||
m_commandIndex.finishSetup();
|
||||
|
||||
return m_sqliteStorage.init();
|
||||
}
|
||||
@@ -54,7 +55,7 @@ void Storage::clear()
|
||||
|
||||
void Storage::clearCaches()
|
||||
{
|
||||
m_tokenIndex.clear();
|
||||
m_searchIndex.clear();
|
||||
m_fileNodeIds.clear();
|
||||
m_hierarchyCache.clear();
|
||||
}
|
||||
@@ -135,11 +136,6 @@ std::vector<FileInfo> Storage::getInfoOnAllFiles() const
|
||||
return fileInfos;
|
||||
}
|
||||
|
||||
const SearchIndex& Storage::getSearchIndex() const
|
||||
{
|
||||
return m_tokenIndex;
|
||||
}
|
||||
|
||||
void Storage::logStats() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
@@ -194,17 +190,6 @@ Id Storage::getIdForNodeWithNameHierarchy(const NameHierarchy& nameHierarchy) co
|
||||
return m_sqliteStorage.getNodeBySerializedName(NameHierarchy::serialize(nameHierarchy)).id;
|
||||
}
|
||||
|
||||
Id Storage::getIdForNodeWithSearchNameHierarchy(const NameHierarchy& nameHierarchy) const
|
||||
{
|
||||
SearchNode* node = m_tokenIndex.getNode(nameHierarchy);
|
||||
if (node)
|
||||
{
|
||||
return node->getFirstTokenId();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Id Storage::getIdForEdge(
|
||||
Edge::EdgeType type, const NameHierarchy& fromNameHierarchy, const NameHierarchy& toNameHierarchy
|
||||
) const
|
||||
@@ -231,77 +216,80 @@ Node::NodeType Storage::getNodeTypeForNodeWithId(Id nodeId) const
|
||||
|
||||
std::vector<SearchMatch> Storage::getAutocompletionMatches(const std::string& query) const
|
||||
{
|
||||
if (query.size() == m_cachedQuery.size() + 1 && query.find(m_cachedQuery) == 0 && m_cachedResults.size())
|
||||
const size_t maxResultCount = 100;
|
||||
std::vector<SearchResult> results = m_commandIndex.search(query, 0);
|
||||
utility::append(results, m_searchIndex.search(query, maxResultCount));
|
||||
|
||||
std::vector<SearchMatch> matches;
|
||||
for (size_t i = 0; i < results.size(); i++)
|
||||
{
|
||||
m_cachedResults = m_tokenIndex.runFuzzySearchCached(query, m_cachedResults);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cachedResults = m_tokenIndex.runFuzzySearch(query);
|
||||
}
|
||||
SearchMatch match;
|
||||
|
||||
m_cachedQuery = query;
|
||||
|
||||
SearchResults results = m_cachedResults;
|
||||
SearchResults commandResults = m_commandIndex.runFuzzySearch(query);
|
||||
results.insert(commandResults.begin(), commandResults.end());
|
||||
|
||||
std::vector<SearchMatch> matches = SearchIndex::getMatches(results, query);
|
||||
|
||||
LOG_INFO_STREAM(<< matches.size() << " matches for \"" << query << "\"");
|
||||
|
||||
if (matches.size() > 100)
|
||||
{
|
||||
matches.resize(100);
|
||||
}
|
||||
|
||||
for (SearchMatch& match : matches)
|
||||
{
|
||||
if (!match.tokenIds.size())
|
||||
if (results[i].elementIds.size() > 0)
|
||||
{
|
||||
match.searchType = SearchMatch::SEARCH_COMMAND;
|
||||
match.typeName = "command";
|
||||
continue;
|
||||
}
|
||||
|
||||
Id elementId = *(match.tokenIds.cbegin());
|
||||
if (m_sqliteStorage.isNode(elementId))
|
||||
{
|
||||
StorageNode node = m_sqliteStorage.getNodeById(elementId);
|
||||
match.nodeType = Node::intToType(node.type);
|
||||
match.typeName = Node::getTypeString(match.nodeType);
|
||||
|
||||
if (intToDefinitionType(node.definitionType) == DEFINITION_NONE && match.nodeType != Node::NODE_UNDEFINED)
|
||||
StorageNode firstNode(0, 0, "", 0);
|
||||
for (std::set<Id>::const_iterator itElementIds = results[i].elementIds.begin(); itElementIds != results[i].elementIds.end(); itElementIds++)
|
||||
{
|
||||
match.typeName = "undefined " + match.typeName;
|
||||
Id elementId = *itElementIds;
|
||||
if (elementId != 0)
|
||||
{
|
||||
StorageNode node = m_sqliteStorage.getNodeById(elementId);
|
||||
match.nameHierarchies.push_back(NameHierarchy::deserialize(node.serializedName));
|
||||
|
||||
if (firstNode.id == 0)
|
||||
{
|
||||
firstNode = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match.text = results[i].text;
|
||||
match.indices = results[i].indices;
|
||||
|
||||
if (firstNode.id != 0)
|
||||
{
|
||||
match.nodeType = Node::intToType(firstNode.type);
|
||||
match.typeName = Node::getTypeString(match.nodeType);
|
||||
|
||||
if (intToDefinitionType(firstNode.definitionType) == DEFINITION_NONE && match.nodeType != Node::NODE_UNDEFINED)
|
||||
{
|
||||
match.typeName = "undefined " + match.typeName;
|
||||
}
|
||||
match.searchType = SearchMatch::SEARCH_TOKEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
match.searchType = SearchMatch::SEARCH_COMMAND;
|
||||
match.typeName = "command";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
match.typeName = Edge::getTypeString(Edge::intToType(m_sqliteStorage.getEdgeById(elementId).type));
|
||||
}
|
||||
|
||||
match.searchType = SearchMatch::SEARCH_TOKEN;
|
||||
matches.push_back(match);
|
||||
}
|
||||
|
||||
std::sort(matches.begin(), matches.end(), [](SearchMatch a, SearchMatch b){
|
||||
return b.text.size() > a.text.size();
|
||||
});
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
std::vector<SearchMatch> Storage::getSearchMatchesForTokenIds(const std::vector<Id>& tokenIds) const
|
||||
std::vector<SearchMatch> Storage::getSearchMatchesForTokenIds(const std::vector<Id>& elementIds) const
|
||||
{
|
||||
// todo: what if all these elements share the same node in the searchindex? in that case there should be only one search match.
|
||||
std::vector<SearchMatch> matches;
|
||||
|
||||
for (Id tokenId : tokenIds)
|
||||
for (Id elementId : elementIds)
|
||||
{
|
||||
SearchMatch match;
|
||||
|
||||
if (m_sqliteStorage.isFile(tokenId))
|
||||
if (m_sqliteStorage.isFile(elementId))
|
||||
{
|
||||
match.nodeType = Node::NODE_FILE;
|
||||
}
|
||||
else if (m_sqliteStorage.isNode(tokenId))
|
||||
else if (m_sqliteStorage.isNode(elementId))
|
||||
{
|
||||
StorageNode node = m_sqliteStorage.getNodeById(tokenId);
|
||||
StorageNode node = m_sqliteStorage.getNodeById(elementId);
|
||||
match.nodeType = Node::intToType(node.type);
|
||||
}
|
||||
else
|
||||
@@ -309,8 +297,9 @@ std::vector<SearchMatch> Storage::getSearchMatchesForTokenIds(const std::vector<
|
||||
continue;
|
||||
}
|
||||
|
||||
match.tokenIds.insert(tokenId);
|
||||
match.nameHierarchy = m_tokenIndex.getNameHierarchyForTokenId(tokenId);
|
||||
NameHierarchy nameHierarchy = NameHierarchy::deserialize(m_sqliteStorage.getNodeById(elementId).serializedName);
|
||||
match.text = nameHierarchy.getQualifiedName();
|
||||
match.nameHierarchies.push_back(nameHierarchy.getQualifiedName());
|
||||
match.searchType = SearchMatch::SEARCH_TOKEN;
|
||||
|
||||
matches.push_back(match);
|
||||
@@ -492,10 +481,9 @@ std::vector<Id> Storage::getTokenIdsForMatches(const std::vector<SearchMatch>& m
|
||||
std::set<Id> idSet;
|
||||
for (const SearchMatch& match : matches)
|
||||
{
|
||||
SearchNode* searchNode = m_tokenIndex.getNode(match.nameHierarchy);
|
||||
if (searchNode)
|
||||
for (size_t i = 0; i < match.nameHierarchies.size(); i++)
|
||||
{
|
||||
utility::append(idSet, searchNode->getTokenIds());
|
||||
idSet.insert(m_sqliteStorage.getNodeBySerializedName(NameHierarchy::serialize(match.nameHierarchies[i])).id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -980,8 +968,9 @@ void Storage::buildSearchIndex()
|
||||
{
|
||||
for (StorageNode node: m_sqliteStorage.getAllNodes())
|
||||
{
|
||||
m_tokenIndex.addTokenId(m_tokenIndex.addNode(NameHierarchy::deserialize(node.serializedName)), node.id);
|
||||
m_searchIndex.addNode(node.id, NameHierarchy::deserialize(node.serializedName));
|
||||
}
|
||||
m_searchIndex.finishSetup();
|
||||
}
|
||||
|
||||
void Storage::buildHierarchyCache()
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
#include "utility/file/FilePath.h"
|
||||
|
||||
#include "data/access/StorageAccess.h"
|
||||
#include "data/HierarchyCache.h"
|
||||
#include "data/graph/token_component/TokenComponentAccess.h"
|
||||
#include "data/location/TokenLocationCollection.h"
|
||||
#include "data/parser/ParserClient.h"
|
||||
#include "data/search/SearchIndex.h"
|
||||
#include "data/HierarchyCache.h"
|
||||
#include "data/SqliteStorage.h"
|
||||
|
||||
#include "data/parser/ParserClientImpl.h"
|
||||
@@ -35,7 +35,6 @@ public:
|
||||
void removeUnusedNames();
|
||||
|
||||
std::vector<FileInfo> getInfoOnAllFiles() const;
|
||||
const SearchIndex& getSearchIndex() const;
|
||||
|
||||
void logStats() const;
|
||||
|
||||
@@ -46,7 +45,6 @@ public:
|
||||
|
||||
// StorageAccess implementation
|
||||
virtual Id getIdForNodeWithNameHierarchy(const NameHierarchy& nameHierarchy) const;
|
||||
virtual Id getIdForNodeWithSearchNameHierarchy(const NameHierarchy& nameHierarchy) const;
|
||||
virtual Id getIdForEdge(
|
||||
Edge::EdgeType type, const NameHierarchy& fromNameHierarchy, const NameHierarchy& toNameHierarchy) const;
|
||||
|
||||
@@ -56,7 +54,7 @@ public:
|
||||
virtual Node::NodeType getNodeTypeForNodeWithId(Id nodeId) const;
|
||||
|
||||
virtual std::vector<SearchMatch> getAutocompletionMatches(const std::string& query) const;
|
||||
virtual std::vector<SearchMatch> getSearchMatchesForTokenIds(const std::vector<Id>& tokenIds) const;
|
||||
virtual std::vector<SearchMatch> getSearchMatchesForTokenIds(const std::vector<Id>& elementIds) const;
|
||||
|
||||
virtual std::shared_ptr<Graph> getGraphForAll() const;
|
||||
virtual std::shared_ptr<Graph> getGraphForActiveTokenIds(const std::vector<Id>& tokenIds, bool activeOnly) const;
|
||||
@@ -105,16 +103,13 @@ private:
|
||||
|
||||
void log(std::string type, std::string str, const ParseLocation& location) const;
|
||||
|
||||
SearchIndex m_tokenIndex;
|
||||
SearchIndex m_commandIndex;
|
||||
SearchIndex m_searchIndex;
|
||||
|
||||
SqliteStorage m_sqliteStorage;
|
||||
|
||||
mutable std::map <FilePath, Id> m_fileNodeIds;
|
||||
HierarchyCache m_hierarchyCache;
|
||||
|
||||
mutable SearchResults m_cachedResults;
|
||||
mutable std::string m_cachedQuery;
|
||||
};
|
||||
|
||||
#endif // STORAGE_H
|
||||
|
||||
@@ -27,7 +27,6 @@ public:
|
||||
virtual ~StorageAccess();
|
||||
|
||||
virtual Id getIdForNodeWithNameHierarchy(const NameHierarchy& nameHierarchy) const = 0;
|
||||
virtual Id getIdForNodeWithSearchNameHierarchy(const NameHierarchy& nameHierarchy) const = 0;
|
||||
virtual Id getIdForEdge(
|
||||
Edge::EdgeType type, const NameHierarchy& fromNameHierarchy, const NameHierarchy& toNameHierarchy) const = 0;
|
||||
|
||||
|
||||
@@ -43,16 +43,6 @@ Id StorageAccessProxy::getIdForNodeWithNameHierarchy(const NameHierarchy& nameHi
|
||||
return 0;
|
||||
}
|
||||
|
||||
Id StorageAccessProxy::getIdForNodeWithSearchNameHierarchy(const NameHierarchy& nameHierarchy) const
|
||||
{
|
||||
if (hasSubject())
|
||||
{
|
||||
return m_subject->getIdForNodeWithSearchNameHierarchy(nameHierarchy);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Id StorageAccessProxy::getIdForEdge(
|
||||
Edge::EdgeType type, const NameHierarchy& fromNameHierarchy, const NameHierarchy& toNameHierarchy
|
||||
) const {
|
||||
|
||||
@@ -14,7 +14,6 @@ public:
|
||||
|
||||
// StorageAccess implementation
|
||||
virtual Id getIdForNodeWithNameHierarchy(const NameHierarchy& nameHierarchy) const;
|
||||
virtual Id getIdForNodeWithSearchNameHierarchy(const NameHierarchy& nameHierarchy) const;
|
||||
virtual Id getIdForEdge(
|
||||
Edge::EdgeType type, const NameHierarchy& fromNameHierarchy, const NameHierarchy& toNameHierarchy) const;
|
||||
|
||||
|
||||
+214
-164
@@ -1,208 +1,258 @@
|
||||
#include "data/search/SearchIndex.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "utility/logging/logging.h"
|
||||
|
||||
#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->getParent());
|
||||
result.push_back(match);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#include "utility/utility.h"
|
||||
|
||||
SearchIndex::SearchIndex()
|
||||
: m_root(nullptr, DELIMITER, 0)
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
SearchIndex::~SearchIndex()
|
||||
{
|
||||
}
|
||||
|
||||
void SearchIndex::clear()
|
||||
void SearchIndex::addNode(Id id, const NameHierarchy& nameHierarchy)
|
||||
{
|
||||
m_root.m_nodes.clear();
|
||||
m_dictionary.clear();
|
||||
m_tokenIds.clear();
|
||||
}
|
||||
Node* currentNode = m_root;
|
||||
|
||||
size_t SearchIndex::getNodeCount() const
|
||||
{
|
||||
return m_root.getNodeCount() - 1;
|
||||
}
|
||||
// we don't use the signature here, so elements with the same signature share the same node in the search index.
|
||||
std::string remaining = nameHierarchy.getQualifiedName();
|
||||
|
||||
size_t SearchIndex::getCharCount() const
|
||||
{
|
||||
return m_dictionary.getCharCount();
|
||||
}
|
||||
|
||||
size_t SearchIndex::getWordCount() const
|
||||
{
|
||||
return m_dictionary.getWordCount();
|
||||
}
|
||||
|
||||
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(NameHierarchy nameHierarchy)
|
||||
{
|
||||
std::deque<Id> nameIds;
|
||||
for (size_t i = 0; i < nameHierarchy.size(); i++)
|
||||
while (remaining.size() > 0)
|
||||
{
|
||||
nameIds.push_back(m_dictionary.getWordId(nameHierarchy[i]->getName()));
|
||||
}
|
||||
|
||||
if (nameIds.size())
|
||||
{
|
||||
return m_root.addNodeRecursive(&nameIds, m_dictionary).get();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SearchNode* SearchIndex::getNode(const NameHierarchy& nameHierarchy) const
|
||||
{
|
||||
std::deque<Id> nameIds = m_dictionary.getWordIdsConst(nameHierarchy);
|
||||
|
||||
if (nameIds.size())
|
||||
{
|
||||
return m_root.getNodeRecursive(&nameIds).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;
|
||||
}
|
||||
|
||||
SearchNode* SearchIndex::getNode(const SearchNode* searchNode) const
|
||||
{
|
||||
if(searchNode == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
std::deque<Id> nameIds = searchNode->getNameIdsRecursive();
|
||||
|
||||
if (nameIds.size())
|
||||
{
|
||||
return m_root.getNodeRecursive(&nameIds).get();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SearchIndex::removeNode(SearchNode* searchNode)
|
||||
{
|
||||
if(searchNode == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
SearchNode* parent = searchNode->getParent();
|
||||
|
||||
if (!parent)
|
||||
{
|
||||
LOG_ERROR_STREAM(<< "SearchNode to be removed has no parent: " << searchNode->getFullName());
|
||||
return;
|
||||
}
|
||||
|
||||
parent->removeSearchNode(searchNode);
|
||||
}
|
||||
|
||||
bool SearchIndex::removeNodeIfUnreferencedRecursive(SearchNode* searchNode)
|
||||
{
|
||||
if(searchNode == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!searchNode->hasTokenIdsRecursive())
|
||||
{
|
||||
SearchNode* parent = searchNode->getParent();
|
||||
|
||||
removeNode(searchNode);
|
||||
|
||||
if (parent && parent != &m_root)
|
||||
bool matchingEdgeFound = false;
|
||||
// has edge starting with c?
|
||||
for (size_t i = 0; i < currentNode->edges.size(); i++)
|
||||
{
|
||||
removeNodeIfUnreferencedRecursive(parent);
|
||||
Edge* currentEdge = currentNode->edges[i];
|
||||
const std::string& edgeString = currentEdge->s;
|
||||
|
||||
int matchCount = 0;
|
||||
for (size_t j = 0; j < edgeString.size() && j < remaining.size(); j++)
|
||||
{
|
||||
if (edgeString[j] != remaining[j])
|
||||
{
|
||||
break;
|
||||
}
|
||||
matchCount++;
|
||||
}
|
||||
|
||||
if (matchCount != 0)
|
||||
{
|
||||
remaining = remaining.substr(matchCount);
|
||||
if (matchCount < edgeString.size())
|
||||
{
|
||||
// split current edge
|
||||
std::shared_ptr<Node> n = std::make_shared<Node>();
|
||||
m_nodes.push_back(n);
|
||||
std::shared_ptr<Edge> e = std::make_shared<Edge>();
|
||||
m_edges.push_back(e);
|
||||
|
||||
n->edges.push_back(e.get());
|
||||
|
||||
e->s = edgeString.substr(matchCount);
|
||||
e->target = currentEdge->target;
|
||||
|
||||
currentEdge->s = edgeString.substr(0, matchCount);
|
||||
currentEdge->target = n.get();
|
||||
}
|
||||
currentNode = currentEdge->target;
|
||||
matchingEdgeFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
if (!matchingEdgeFound)
|
||||
{
|
||||
std::shared_ptr<Node> n = std::make_shared<Node>();
|
||||
m_nodes.push_back(n);
|
||||
std::shared_ptr<Edge> e = std::make_shared<Edge>();
|
||||
m_edges.push_back(e);
|
||||
|
||||
e->s = remaining;
|
||||
e->target = n.get();
|
||||
|
||||
currentNode->edges.push_back(e.get());
|
||||
currentNode = n.get();
|
||||
|
||||
remaining = "";
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
currentNode->elementIds.insert(id);
|
||||
}
|
||||
|
||||
void SearchIndex::addTokenId(SearchNode* node, Id tokenId)
|
||||
void SearchIndex::finishSetup()
|
||||
{
|
||||
if(node == nullptr)
|
||||
for (size_t i = 0; i < m_root->edges.size(); i++)
|
||||
{
|
||||
LOG_ERROR("Node points to nullptr: Can't add tokenid");
|
||||
return;
|
||||
populateEdgeGate(m_root->edges[i]);
|
||||
}
|
||||
node->addTokenId(tokenId);
|
||||
m_tokenIds.emplace(tokenId, node);
|
||||
}
|
||||
|
||||
NameHierarchy SearchIndex::getNameHierarchyForTokenId(Id tokenId) const
|
||||
void SearchIndex::clear()
|
||||
{
|
||||
std::map<Id, SearchNode*>::const_iterator it = m_tokenIds.find(tokenId);
|
||||
m_nodes.clear();
|
||||
m_edges.clear();
|
||||
|
||||
if (it != m_tokenIds.end())
|
||||
std::shared_ptr<Node> n = std::make_shared<Node>();
|
||||
m_nodes.push_back(n);
|
||||
|
||||
m_root = n.get();
|
||||
}
|
||||
|
||||
std::vector<SearchResult> SearchIndex::search(const std::string& query, size_t maxResultCount) const
|
||||
{
|
||||
std::string lowerCaseQuery = "";
|
||||
for (size_t i = 0; i < query.size(); i++)
|
||||
{
|
||||
SearchNode* node = it->second;
|
||||
return node->getNameHierarchy();
|
||||
lowerCaseQuery += tolower(query[i]);
|
||||
}
|
||||
|
||||
return NameHierarchy();
|
||||
Path startPath;
|
||||
startPath.node = m_root;
|
||||
std::vector<Path> paths = search(startPath, lowerCaseQuery);
|
||||
|
||||
// scoring paths
|
||||
std::vector<std::pair<float, Path>> scoredPaths;
|
||||
for (size_t i = 0; i < paths.size(); i++)
|
||||
{
|
||||
const std::vector<size_t>& currentIndices = paths[i].indices;
|
||||
|
||||
int gapCount = 0;
|
||||
for (size_t j = 1; j < currentIndices.size(); j++)
|
||||
{
|
||||
if (currentIndices[j] - currentIndices[j-1] > 1)
|
||||
{
|
||||
gapCount++;
|
||||
}
|
||||
}
|
||||
float score = (1.0f / (gapCount + 1)) + (1.0f / (paths[i].text.size() + 1));
|
||||
scoredPaths.push_back(std::make_pair(score, paths[i]));
|
||||
}
|
||||
|
||||
// sorting paths
|
||||
std::sort(scoredPaths.begin(), scoredPaths.end(), [](
|
||||
std::pair<float, Path> a,
|
||||
std::pair<float, Path> b)
|
||||
{
|
||||
return b.first < a.first;
|
||||
}
|
||||
);
|
||||
|
||||
// preparing results
|
||||
std::vector<SearchResult> searchResults;
|
||||
for (size_t i = 0; i < scoredPaths.size() && (maxResultCount == 0 || searchResults.size() < maxResultCount); i++)
|
||||
{
|
||||
std::vector<Path> currentPaths;
|
||||
currentPaths.push_back(scoredPaths[i].second);
|
||||
|
||||
while (currentPaths.size() > 0)
|
||||
{
|
||||
std::vector<Path> nextPaths;
|
||||
|
||||
for (size_t j = 0; j < currentPaths.size(); j++)
|
||||
{
|
||||
Path& currentPath = currentPaths[j];
|
||||
if (currentPath.node->elementIds.size() > 0 && (maxResultCount == 0 || searchResults.size() < maxResultCount))
|
||||
{
|
||||
SearchResult result;
|
||||
result.elementIds = currentPath.node->elementIds;
|
||||
result.indices = currentPath.indices;
|
||||
result.text = currentPath.text;
|
||||
searchResults.push_back(result);
|
||||
}
|
||||
|
||||
for (size_t k = 0; k < currentPath.node->edges.size(); k++)
|
||||
{
|
||||
Path nextPath;
|
||||
nextPath.indices = currentPath.indices;
|
||||
nextPath.node = currentPath.node->edges[k]->target;
|
||||
nextPath.text = currentPath.text + currentPath.node->edges[k]->s;
|
||||
nextPaths.push_back(nextPath);
|
||||
}
|
||||
}
|
||||
|
||||
currentPaths = nextPaths;
|
||||
|
||||
if (!(maxResultCount == 0 || searchResults.size() < maxResultCount))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return searchResults;
|
||||
}
|
||||
|
||||
SearchResults SearchIndex::runFuzzySearch(const std::string& query) const
|
||||
void SearchIndex::populateEdgeGate(Edge* e)
|
||||
{
|
||||
return m_root.runFuzzySearch(query);
|
||||
Node* target = e->target;
|
||||
for (size_t i = 0; i < target->edges.size(); i++)
|
||||
{
|
||||
Edge* targetEdge = target->edges[i];
|
||||
populateEdgeGate(targetEdge);
|
||||
utility::append(e->gate, targetEdge->gate);
|
||||
}
|
||||
for (size_t i = 0; i < e->s.size(); i++)
|
||||
{
|
||||
e->gate.insert(tolower(e->s[i]));
|
||||
}
|
||||
}
|
||||
|
||||
SearchResults SearchIndex::runFuzzySearchCached(const std::string& query, const SearchResults& searchResults) const
|
||||
std::vector<SearchIndex::Path> SearchIndex::search(const Path& path, const std::string& remainingQuery) const
|
||||
{
|
||||
return m_root.runFuzzySearchCached(query, searchResults);
|
||||
}
|
||||
std::vector<Path> results;
|
||||
|
||||
std::vector<SearchMatch> SearchIndex::runFuzzySearchAndGetMatches(const std::string& query) const
|
||||
{
|
||||
return getMatches(runFuzzySearch(query), query);
|
||||
}
|
||||
if (remainingQuery.size() == 0)
|
||||
{
|
||||
results.push_back(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i < path.node->edges.size(); i++)
|
||||
{
|
||||
const Edge* currentEdge = path.node->edges[i];
|
||||
|
||||
const std::string SearchIndex::DELIMITER = "::";
|
||||
// test if s passes the edge's gate.
|
||||
bool passesGate = true;
|
||||
for (size_t j = 0; j < remainingQuery.size(); j++)
|
||||
{
|
||||
if (currentEdge->gate.find(tolower(remainingQuery[j])) == currentEdge->gate.end())
|
||||
{
|
||||
passesGate = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& ostream, const SearchIndex& index)
|
||||
{
|
||||
ostream << "SearchIndex:\n";
|
||||
ostream << &index.m_root;
|
||||
return ostream;
|
||||
if (passesGate)
|
||||
{
|
||||
// consume characters for edge
|
||||
const std::string& edgeString = currentEdge->s;
|
||||
|
||||
std::vector<size_t> currentFoundIds = path.indices;
|
||||
std::string currentRemainingQuery = remainingQuery;
|
||||
|
||||
for (size_t j = 0; j < edgeString.size() && currentRemainingQuery.size() > 0; j++)
|
||||
{
|
||||
if (currentRemainingQuery[0] == tolower(edgeString[j]))
|
||||
{
|
||||
currentFoundIds.push_back(path.text.size() + j);
|
||||
currentRemainingQuery = currentRemainingQuery.substr(1);
|
||||
}
|
||||
}
|
||||
|
||||
Path currentPath;
|
||||
currentPath.node = currentEdge->target;
|
||||
currentPath.indices = currentFoundIds;
|
||||
currentPath.text = path.text + edgeString;
|
||||
|
||||
utility::append(results, search(currentPath, currentRemainingQuery));
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
@@ -1,59 +1,66 @@
|
||||
#ifndef SEARCH_INDEX_H
|
||||
#define SEARCH_INDEX_H
|
||||
|
||||
#include <ostream>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "utility/text/Dictionary.h"
|
||||
#include "utility/types.h"
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "data/name/NameHierarchy.h"
|
||||
#include "data/search/SearchNode.h"
|
||||
#include "utility/types.h"
|
||||
|
||||
struct SearchResult
|
||||
{
|
||||
std::string text;
|
||||
std::set<Id> elementIds;
|
||||
std::vector<size_t> indices;
|
||||
};
|
||||
|
||||
class SearchIndex
|
||||
{
|
||||
public:
|
||||
static std::vector<SearchMatch> getMatches(const SearchResults& searchResults, const std::string& query);
|
||||
|
||||
SearchIndex();
|
||||
virtual ~SearchIndex();
|
||||
|
||||
void addNode(Id id, const NameHierarchy& nameHierarchy);
|
||||
void finishSetup();
|
||||
void clear();
|
||||
|
||||
size_t getNodeCount() const;
|
||||
size_t getCharCount() const;
|
||||
size_t getWordCount() const;
|
||||
|
||||
Id getWordId(const std::string& word);
|
||||
const std::string& getWord(Id wordId) const;
|
||||
|
||||
SearchNode* addNode(NameHierarchy nameHierarchy);
|
||||
SearchNode* getNode(const NameHierarchy& nameHierarchy) const;
|
||||
SearchNode* getNode(const std::string& fullName) const;
|
||||
SearchNode* getNode(const SearchNode* searchNode) const;
|
||||
|
||||
void removeNode(SearchNode* searchNode);
|
||||
bool removeNodeIfUnreferencedRecursive(SearchNode* searchNode);
|
||||
|
||||
void addTokenId(SearchNode* node, Id tokenId);
|
||||
NameHierarchy getNameHierarchyForTokenId(Id tokenId) const;
|
||||
|
||||
SearchResults runFuzzySearch(const std::string& query) const;
|
||||
SearchResults runFuzzySearchCached(const std::string& query, const SearchResults& searchResults) const;
|
||||
std::vector<SearchMatch> runFuzzySearchAndGetMatches(const std::string& query) const;
|
||||
|
||||
static const std::string DELIMITER;
|
||||
// maxResultCount == 0 means "no restriction".
|
||||
std::vector<SearchResult> search(const std::string& query, size_t maxResultCount) const;
|
||||
|
||||
private:
|
||||
SearchNode m_root;
|
||||
Dictionary m_dictionary;
|
||||
struct Node;
|
||||
struct Edge;
|
||||
|
||||
std::map<Id, SearchNode*> m_tokenIds;
|
||||
struct Node
|
||||
{
|
||||
std::set<Id> elementIds;
|
||||
std::vector<Edge*> edges;
|
||||
};
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& ostream, const SearchIndex& index);
|
||||
struct Edge
|
||||
{
|
||||
Node* target;
|
||||
std::string s;
|
||||
std::unordered_set<char> gate;
|
||||
};
|
||||
|
||||
struct Path
|
||||
{
|
||||
std::string text;
|
||||
std::vector<size_t> indices;
|
||||
Node* node;
|
||||
};
|
||||
|
||||
void populateEdgeGate(Edge* e);
|
||||
std::vector<Path> search(const Path& path, const std::string& remainingQuery) const;
|
||||
|
||||
std::vector<std::shared_ptr<Node>> m_nodes;
|
||||
std::vector<std::shared_ptr<Edge>> m_edges;
|
||||
Node* m_root;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& ostream, const SearchIndex& index);
|
||||
|
||||
#endif // SEARCH_INDEX_H
|
||||
|
||||
@@ -48,7 +48,7 @@ std::string SearchMatch::searchMatchesToString(const std::vector<SearchMatch>& m
|
||||
SearchMatch SearchMatch::createCommand(CommandType type)
|
||||
{
|
||||
SearchMatch match;
|
||||
match.nameHierarchy = NameHierarchy(getCommandName(type));
|
||||
match.text = getCommandName(type);
|
||||
match.typeName = "command";
|
||||
match.searchType = SEARCH_COMMAND;
|
||||
return match;
|
||||
@@ -74,7 +74,7 @@ SearchMatch::SearchMatch()
|
||||
}
|
||||
|
||||
SearchMatch::SearchMatch(const std::string& query)
|
||||
: nameHierarchy(query)
|
||||
: text(query)
|
||||
, typeName("")
|
||||
, searchType(SEARCH_NONE)
|
||||
{
|
||||
@@ -87,7 +87,7 @@ bool SearchMatch::isValid() const
|
||||
|
||||
void SearchMatch::print(std::ostream& ostream) const
|
||||
{
|
||||
ostream << weight << '\t' << nameHierarchy.getQualifiedName() << std::endl << '\t';
|
||||
ostream << text << std::endl << '\t';
|
||||
size_t i = 0;
|
||||
for (size_t index : indices)
|
||||
{
|
||||
@@ -104,7 +104,7 @@ void SearchMatch::print(std::ostream& ostream) const
|
||||
|
||||
std::string SearchMatch::getFullName() const
|
||||
{
|
||||
return nameHierarchy.getQualifiedName();
|
||||
return text;
|
||||
}
|
||||
|
||||
std::string SearchMatch::getNodeTypeAsString() const
|
||||
|
||||
@@ -44,16 +44,13 @@ struct SearchMatch
|
||||
std::string getNodeTypeAsString() const;
|
||||
std::string getSearchTypeName() const;
|
||||
|
||||
NameHierarchy nameHierarchy;
|
||||
std::string text;
|
||||
std::string typeName;
|
||||
|
||||
Node::NodeType nodeType;
|
||||
SearchType searchType;
|
||||
|
||||
std::set<Id> tokenIds;
|
||||
|
||||
std::vector<size_t> indices;
|
||||
size_t weight;
|
||||
|
||||
std::vector<NameHierarchy> nameHierarchies;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,455 +0,0 @@
|
||||
#include "data/search/SearchNode.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "utility/text/Dictionary.h"
|
||||
|
||||
#include "data/name/NameHierarchy.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()
|
||||
{
|
||||
}
|
||||
|
||||
size_t SearchNode::getNodeCount() const
|
||||
{
|
||||
size_t count = 1;
|
||||
|
||||
for (const std::pair<Id, std::shared_ptr<SearchNode>>& p : m_nodes)
|
||||
{
|
||||
count += p.second->getNodeCount();
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
const std::string& SearchNode::getName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
NameHierarchy SearchNode::getNameHierarchy() const
|
||||
{
|
||||
NameHierarchy nameHierarchy;
|
||||
const SearchNode* parent = getParent();
|
||||
if (parent && parent->m_nameId)
|
||||
{
|
||||
nameHierarchy = parent->getNameHierarchy();
|
||||
}
|
||||
nameHierarchy.push(std::make_shared<NameElement>(getName()));
|
||||
return nameHierarchy;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
std::deque<Id> SearchNode::getNameIdsRecursive() const
|
||||
{
|
||||
std::deque<Id> ids;
|
||||
|
||||
ids.push_front(m_nameId);
|
||||
|
||||
SearchNode* parent = m_parent;
|
||||
while (parent && parent->m_nameId)
|
||||
{
|
||||
ids.push_front(parent->getNameId());
|
||||
parent = parent->getParent();
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
Id SearchNode::getFirstTokenId() const
|
||||
{
|
||||
if (m_tokenIds.size())
|
||||
{
|
||||
return *m_tokenIds.begin();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::set<Id>& SearchNode::getTokenIds() const
|
||||
{
|
||||
return m_tokenIds;
|
||||
}
|
||||
|
||||
bool SearchNode::hasTokenIdsRecursive() const
|
||||
{
|
||||
if (m_tokenIds.size())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const std::pair<Id, std::shared_ptr<SearchNode>>& p : m_nodes)
|
||||
{
|
||||
if (p.second->hasTokenIdsRecursive())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SearchNode::addTokenId(Id tokenId)
|
||||
{
|
||||
m_tokenIds.insert(tokenId);
|
||||
}
|
||||
|
||||
void SearchNode::removeTokenId(Id tokenId)
|
||||
{
|
||||
m_tokenIds.erase(tokenId);
|
||||
}
|
||||
|
||||
SearchNode* SearchNode::getParent() const
|
||||
{
|
||||
if (m_parent)
|
||||
{
|
||||
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::map<Id, std::shared_ptr<SearchNode>>& SearchNode::getChildren() const
|
||||
{
|
||||
return m_nodes;
|
||||
}
|
||||
|
||||
SearchResults SearchNode::runFuzzySearch(const std::string& query) const
|
||||
{
|
||||
SearchResults result;
|
||||
|
||||
for (const std::pair<Id, std::shared_ptr<SearchNode>>& p : m_nodes)
|
||||
{
|
||||
FuzzyMap m = p.second->fuzzyMatchRecursive(query, 0, 0, 0);
|
||||
for (const std::pair<size_t, const SearchNode*>& p2 : m)
|
||||
{
|
||||
addResultsRecursive(&result, p2.first, p2.second, p.second.get());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
SearchResults SearchNode::runFuzzySearchCached(const std::string& query, const SearchResults& searchResults) const
|
||||
{
|
||||
SearchResults result;
|
||||
|
||||
std::set<const SearchNode*> nodes;
|
||||
for (const SearchResult& r : searchResults)
|
||||
{
|
||||
nodes.insert(r.parent);
|
||||
}
|
||||
|
||||
for (const SearchNode* n : nodes)
|
||||
{
|
||||
FuzzyMap m = n->fuzzyMatchRecursive(query, 0, 0, 0);
|
||||
for (const std::pair<size_t, const SearchNode*>& p : m)
|
||||
{
|
||||
addResultsRecursive(&result, p.first, p.second, n);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
SearchResults SearchNode::runFuzzySearchOnSelf(const std::string& query) const
|
||||
{
|
||||
SearchResults result;
|
||||
FuzzyMap m = fuzzyMatchRecursive(query, 0, 0, 0);
|
||||
for (const std::pair<size_t, const SearchNode*>& p : m)
|
||||
{
|
||||
addResultsRecursive(&result, p.first, p.second, this);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void SearchNode::addResultsRecursive(
|
||||
SearchResults* results, size_t weight, const SearchNode* node, const SearchNode* parent
|
||||
) const {
|
||||
results->insert(SearchResult(weight, node, parent));
|
||||
|
||||
for (const std::pair<Id, std::shared_ptr<SearchNode>>& p : node->m_nodes)
|
||||
{
|
||||
addResultsRecursive(results, weight, p.second.get(), parent);
|
||||
}
|
||||
}
|
||||
|
||||
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.emplace(nameId, 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;
|
||||
}
|
||||
|
||||
void SearchNode::removeSearchNode(SearchNode* node)
|
||||
{
|
||||
std::map<Id, std::shared_ptr<SearchNode>>::iterator it = m_nodes.find(node->getNameId());
|
||||
|
||||
if (it != m_nodes.end())
|
||||
{
|
||||
m_nodes.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
SearchMatch SearchNode::fuzzyMatchData(const std::string& query, const SearchNode* parent) const
|
||||
{
|
||||
SearchMatch data;
|
||||
data.nameHierarchy = getNameHierarchy();
|
||||
data.tokenIds = m_tokenIds;
|
||||
data.weight = 0;
|
||||
|
||||
size_t pos = 0;
|
||||
size_t size = 0;
|
||||
|
||||
const SearchNode* root = parent;
|
||||
std::deque<const SearchNode*> nodes = getNodesToParent(parent);
|
||||
if (!nodes.size())
|
||||
{
|
||||
nodes.push_back(this);
|
||||
root = root->getParent();
|
||||
}
|
||||
|
||||
while (root && root->getNameId())
|
||||
{
|
||||
size += root->getName().size() + SearchIndex::DELIMITER.size();
|
||||
root = root->getParent();
|
||||
}
|
||||
|
||||
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 (const std::pair<Id, std::shared_ptr<SearchNode>>& p : m_nodes)
|
||||
{
|
||||
FuzzyMap m = p.second->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;
|
||||
|
||||
size_t ql = query.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char last = '\0';
|
||||
size_t nl = m_name.size();
|
||||
for (size_t i = 0; i < nl; i++)
|
||||
{
|
||||
char c = m_name[i];
|
||||
char next = (i + 1 == nl ? '\0' : m_name[i + 1]);
|
||||
|
||||
if (tolower(query[pos]) == tolower(c))
|
||||
{
|
||||
weight += std::max<size_t>(100 / sqrt(size + i + 1), 1);
|
||||
|
||||
if (matchCount)
|
||||
{
|
||||
weight += matchCount * matchCount * 10;
|
||||
}
|
||||
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
weight += 20;
|
||||
}
|
||||
|
||||
if (last == '_' || next == '_' || next == '\0')
|
||||
{
|
||||
weight += 20;
|
||||
}
|
||||
else if ((tolower(c) != c && tolower(next) == next) || (tolower(c) == c && tolower(next) != next))
|
||||
{
|
||||
weight += 20;
|
||||
}
|
||||
|
||||
matchCount++;
|
||||
|
||||
pos++;
|
||||
if (indices)
|
||||
{
|
||||
indices->push_back(size + i);
|
||||
}
|
||||
|
||||
if (pos == ql || query[pos] == ':')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
matchCount = 0;
|
||||
}
|
||||
|
||||
last = c;
|
||||
}
|
||||
|
||||
return std::pair<size_t, size_t>(pos, weight);
|
||||
}
|
||||
|
||||
std::shared_ptr<SearchNode> SearchNode::getChildWithNameId(Id nameId) const
|
||||
{
|
||||
std::map<Id, std::shared_ptr<SearchNode>>::const_iterator it = m_nodes.find(nameId);
|
||||
|
||||
if (it != m_nodes.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& ostream, const SearchNode* node)
|
||||
{
|
||||
ostream << node->m_name;
|
||||
|
||||
for (Id tokenId : node->m_tokenIds)
|
||||
{
|
||||
ostream << ' ' << tokenId;
|
||||
}
|
||||
|
||||
ostream << '\n';
|
||||
|
||||
for (const std::pair<Id, std::shared_ptr<SearchNode>> p : node->m_nodes)
|
||||
{
|
||||
ostream << p.second.get();
|
||||
}
|
||||
|
||||
return ostream;
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
#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 NameHierarchy;
|
||||
class SearchIndex;
|
||||
struct SearchMatch;
|
||||
|
||||
class SearchNode
|
||||
{
|
||||
public:
|
||||
SearchNode(SearchNode* parent, const std::string& name, Id nameId);
|
||||
~SearchNode();
|
||||
|
||||
size_t getNodeCount() const;
|
||||
|
||||
const std::string& getName() const;
|
||||
NameHierarchy getNameHierarchy() const;
|
||||
std::string getFullName() const;
|
||||
|
||||
Id getNameId() const;
|
||||
std::deque<Id> getNameIdsRecursive() const;
|
||||
|
||||
Id getFirstTokenId() const;
|
||||
const std::set<Id>& getTokenIds() const;
|
||||
bool hasTokenIdsRecursive() const;
|
||||
|
||||
void addTokenId(Id tokenId);
|
||||
void removeTokenId(Id tokenId);
|
||||
|
||||
SearchNode* getParent() const;
|
||||
std::deque<SearchNode*> getParentsWithoutTokenId();
|
||||
|
||||
const std::map<Id, std::shared_ptr<SearchNode>>& getChildren() const;
|
||||
|
||||
SearchResults runFuzzySearch(const std::string& query) const;
|
||||
SearchResults runFuzzySearchCached(const std::string& query, const SearchResults& searchResults) const;
|
||||
SearchResults runFuzzySearchOnSelf(const std::string& query) const;
|
||||
|
||||
void addResultsRecursive(SearchResults* results, size_t weight, const SearchNode* node, const SearchNode* parent) 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;
|
||||
|
||||
void removeSearchNode(SearchNode* node);
|
||||
|
||||
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::map<Id, std::shared_ptr<SearchNode>> m_nodes;
|
||||
SearchNode* m_parent;
|
||||
|
||||
std::set<Id> m_tokenIds;
|
||||
|
||||
const std::string& m_name;
|
||||
const Id m_nameId;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& ostream, const SearchNode* node);
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& ostream, const SearchNode* node);
|
||||
|
||||
#endif // SEARCH_NODE_H
|
||||
@@ -1,34 +0,0 @@
|
||||
#include "data/search/SearchResult.h"
|
||||
|
||||
#include "utility/utilityString.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;
|
||||
}
|
||||
|
||||
std::string lhsLow = utility::toLowerCase(lhs.node->getFullName());
|
||||
std::string rhsLow = utility::toLowerCase(rhs.node->getFullName());
|
||||
if (lhsLow != rhsLow)
|
||||
{
|
||||
return lhsLow < rhsLow;
|
||||
}
|
||||
|
||||
return lhs.node->getFirstTokenId() < rhs.node->getFirstTokenId();
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
#ifndef SEARCH_RESULT_H
|
||||
#define SEARCH_RESULT_H
|
||||
|
||||
#include <set>
|
||||
#include <stddef.h>
|
||||
|
||||
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
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <deque>
|
||||
#include <set>
|
||||
#include <time.h>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "boost/date_time/posix_time/posix_time.hpp"
|
||||
|
||||
@@ -30,6 +31,9 @@ namespace utility
|
||||
template<typename T>
|
||||
void append(std::set<T>& a, const std::set<T>& b);
|
||||
|
||||
template<typename T>
|
||||
void append(std::unordered_set<T>& a, const std::unordered_set<T>& b);
|
||||
|
||||
template<typename T>
|
||||
std::vector<T> toVector(const std::deque<T>& d);
|
||||
|
||||
@@ -76,6 +80,12 @@ void utility::append(std::set<T>& a, const std::set<T>& b)
|
||||
a.insert(b.begin(), b.end());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void utility::append(std::unordered_set<T>& a, const std::unordered_set<T>& b)
|
||||
{
|
||||
a.insert(b.begin(), b.end());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::vector<T> utility::toVector(const std::deque<T>& d)
|
||||
{
|
||||
|
||||
@@ -396,7 +396,7 @@ void QtSmartSearchBox::onTextEdited(const QString& text)
|
||||
}
|
||||
}
|
||||
|
||||
if (match.nameHierarchy.size() && !m_allowMultipleElements)
|
||||
if (match.text.size() && !m_allowMultipleElements)
|
||||
{
|
||||
if (m_matches.size())
|
||||
{
|
||||
@@ -415,7 +415,7 @@ void QtSmartSearchBox::onTextEdited(const QString& text)
|
||||
layoutElements();
|
||||
}
|
||||
|
||||
if (match.nameHierarchy.size() || m_elements.size())
|
||||
if (match.text.size() || m_elements.size())
|
||||
{
|
||||
requestAutoCompletions();
|
||||
}
|
||||
@@ -446,7 +446,7 @@ void QtSmartSearchBox::onAutocompletionActivated(const SearchMatch& match)
|
||||
{
|
||||
addMatchAndUpdate(match);
|
||||
|
||||
if (match.nameHierarchy.size())
|
||||
if (match.text.size())
|
||||
{
|
||||
search();
|
||||
}
|
||||
@@ -516,7 +516,7 @@ void QtSmartSearchBox::moveCursorTo(int target)
|
||||
|
||||
void QtSmartSearchBox::addMatch(const SearchMatch& match)
|
||||
{
|
||||
if (!match.nameHierarchy.size())
|
||||
if (!match.text.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -543,7 +543,7 @@ void QtSmartSearchBox::addMatch(const SearchMatch& match)
|
||||
|
||||
void QtSmartSearchBox::addMatchAndUpdate(const SearchMatch& match)
|
||||
{
|
||||
if (match.nameHierarchy.size())
|
||||
if (match.text.size())
|
||||
{
|
||||
m_oldText.clear();
|
||||
clearLineEdit();
|
||||
|
||||
+52
-259
@@ -3,302 +3,95 @@
|
||||
#include "utility/utilityString.h"
|
||||
|
||||
#include "data/search/SearchIndex.h"
|
||||
#include "data/search/SearchMatch.h"
|
||||
|
||||
class SearchIndexTestSuite : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
void test_add_node()
|
||||
|
||||
void test_search_index_finds_id_of_element_added()
|
||||
{
|
||||
SearchIndex index;
|
||||
SearchNode* node = index.addNode(createNameHierarchy("util"));
|
||||
index.addNode(1, NameHierarchy::deserialize("foo\tvoid\r() const"));
|
||||
index.finishSetup();
|
||||
std::vector<SearchResult> results = index.search("oo", 0);
|
||||
|
||||
TS_ASSERT(node);
|
||||
TS_ASSERT_EQUALS("util", node->getName());
|
||||
TS_ASSERT_EQUALS("util", node->getFullName());
|
||||
|
||||
TS_ASSERT(node->getNameId());
|
||||
TS_ASSERT(!node->getFirstTokenId());
|
||||
TS_ASSERT(node->getParent());
|
||||
TS_ASSERT(!node->getParent()->getNameId());
|
||||
TS_ASSERT_EQUALS(1, results.size());
|
||||
TS_ASSERT_EQUALS(1, results[0].elementIds.size());
|
||||
TS_ASSERT_DIFFERS(results[0].elementIds.end(), results[0].elementIds.find(1));
|
||||
}
|
||||
|
||||
void test_get_node()
|
||||
void test_search_index_finds_correct_indices_for_query()
|
||||
{
|
||||
SearchIndex index;
|
||||
index.addNode(createNameHierarchy("util"));
|
||||
SearchNode* node = index.getNode("util");
|
||||
index.addNode(1, NameHierarchy::deserialize("foo\tvoid\r() const"));
|
||||
index.finishSetup();
|
||||
std::vector<SearchResult> results = index.search("oo", 0);
|
||||
|
||||
TS_ASSERT(node);
|
||||
TS_ASSERT_EQUALS("util", node->getName());
|
||||
TS_ASSERT_EQUALS("util", node->getFullName());
|
||||
|
||||
TS_ASSERT(node->getNameId());
|
||||
TS_ASSERT(!node->getFirstTokenId());
|
||||
TS_ASSERT(node->getParent());
|
||||
TS_ASSERT(!node->getParent()->getNameId());
|
||||
|
||||
node = index.getNode("math");
|
||||
TS_ASSERT(!node);
|
||||
TS_ASSERT_EQUALS(1, results.size());
|
||||
TS_ASSERT_EQUALS(2, results[0].indices.size());
|
||||
TS_ASSERT_EQUALS(1, results[0].indices[0]);
|
||||
TS_ASSERT_EQUALS(2, results[0].indices[1]);
|
||||
}
|
||||
|
||||
void test_add_hierarchy_node()
|
||||
void test_search_index_finds_ids_for_ambiguous_query()
|
||||
{
|
||||
SearchIndex index;
|
||||
SearchNode* node = index.addNode(createNameHierarchy("util::math::pow"));
|
||||
index.addNode(1, NameHierarchy::deserialize("for\tvoid\r() const"));
|
||||
index.addNode(2, NameHierarchy::deserialize("fos\tvoid\r() const"));
|
||||
index.finishSetup();
|
||||
std::vector<SearchResult> results = index.search("fo", 0);
|
||||
|
||||
TS_ASSERT(node);
|
||||
TS_ASSERT_EQUALS("pow", node->getName());
|
||||
TS_ASSERT_EQUALS("util::math::pow", node->getFullName());
|
||||
|
||||
TS_ASSERT(node->getNameId());
|
||||
TS_ASSERT(!node->getFirstTokenId());
|
||||
|
||||
TS_ASSERT(node->getParent());
|
||||
TS_ASSERT_EQUALS("math", node->getParent()->getName());
|
||||
|
||||
TS_ASSERT(node->getParent()->getParent());
|
||||
TS_ASSERT_EQUALS("util", node->getParent()->getParent()->getName());
|
||||
TS_ASSERT_EQUALS(2, results.size());
|
||||
TS_ASSERT_EQUALS(1, results[0].elementIds.size());
|
||||
TS_ASSERT_DIFFERS(results[0].elementIds.end(), results[0].elementIds.find(1));
|
||||
TS_ASSERT_EQUALS(1, results[1].elementIds.size());
|
||||
TS_ASSERT_DIFFERS(results[1].elementIds.end(), results[1].elementIds.find(2));
|
||||
}
|
||||
|
||||
void test_reuse_hierarchy_node()
|
||||
void test_search_index_does_not_find_anything_after_clear()
|
||||
{
|
||||
SearchIndex index;
|
||||
SearchNode* node1 = index.addNode(createNameHierarchy("math::pow"));
|
||||
SearchNode* node2 = index.addNode(createNameHierarchy("math::floor"));
|
||||
|
||||
TS_ASSERT(node1);
|
||||
TS_ASSERT(node2);
|
||||
|
||||
TS_ASSERT_EQUALS("pow", node1->getName());
|
||||
TS_ASSERT_EQUALS("floor", node2->getName());
|
||||
|
||||
TS_ASSERT_EQUALS(node1->getParent(), node2->getParent());
|
||||
}
|
||||
|
||||
void test_remove_nodes()
|
||||
{
|
||||
SearchIndex index;
|
||||
index.addNode(createNameHierarchy("util::math::pow"));
|
||||
index.addNode(createNameHierarchy("util::math::floor"));
|
||||
|
||||
index.removeNode(index.getNode("util::math::pow"));
|
||||
|
||||
TS_ASSERT(!index.getNode("util::math::pow"));
|
||||
TS_ASSERT(index.getNode("util::math::floor"));
|
||||
TS_ASSERT(index.getNode("util::math"));
|
||||
|
||||
index.removeNode(index.getNode("util::math"));
|
||||
|
||||
TS_ASSERT(!index.getNode("util::math::floor"));
|
||||
TS_ASSERT(!index.getNode("util::math"));
|
||||
TS_ASSERT(index.getNode("util"));
|
||||
}
|
||||
|
||||
void test_remove_unreferenced_nodes()
|
||||
{
|
||||
SearchIndex index;
|
||||
SearchNode* node1 = index.addNode(createNameHierarchy("util::math::pow"));
|
||||
SearchNode* node2 = index.addNode(createNameHierarchy("util::math::floor"));
|
||||
|
||||
node1->addTokenId(1);
|
||||
node2->addTokenId(2);
|
||||
|
||||
TS_ASSERT(index.getNode("util")->hasTokenIdsRecursive());
|
||||
|
||||
TS_ASSERT(!index.removeNodeIfUnreferencedRecursive(index.getNode("util")));
|
||||
TS_ASSERT(!index.removeNodeIfUnreferencedRecursive(index.getNode("util::math")));
|
||||
TS_ASSERT(!index.removeNodeIfUnreferencedRecursive(index.getNode("util::math::pow")));
|
||||
|
||||
node1->removeTokenId(1);
|
||||
|
||||
TS_ASSERT(index.removeNodeIfUnreferencedRecursive(index.getNode("util::math::pow")));
|
||||
TS_ASSERT(!index.getNode("util::math::pow"));
|
||||
TS_ASSERT(index.getNode("util::math"));
|
||||
TS_ASSERT(index.getNode("util"));
|
||||
|
||||
node2->removeTokenId(2);
|
||||
|
||||
TS_ASSERT(index.removeNodeIfUnreferencedRecursive(index.getNode("util::math")));
|
||||
|
||||
TS_ASSERT(!index.getNode("util::math"));
|
||||
TS_ASSERT(!index.getNode("util"));
|
||||
}
|
||||
|
||||
void test_clear()
|
||||
{
|
||||
SearchIndex index;
|
||||
index.addNode(createNameHierarchy("math"));
|
||||
index.addNode(createNameHierarchy("string"));
|
||||
|
||||
TS_ASSERT(index.getNode("math"));
|
||||
|
||||
index.addNode(1, NameHierarchy::deserialize("foo\tvoid\r() const"));
|
||||
index.finishSetup();
|
||||
index.clear();
|
||||
std::vector<SearchResult> results = index.search("oo", 0);
|
||||
|
||||
TS_ASSERT(!index.getNode("math"));
|
||||
TS_ASSERT(!index.getNode("string"));
|
||||
TS_ASSERT_EQUALS(0, results.size());
|
||||
}
|
||||
|
||||
void test_fuzzy_matching()
|
||||
void test_search_index_does_not_find_all_results_when_max_amount_is_limited()
|
||||
{
|
||||
SearchIndex index;
|
||||
index.addNode(createNameHierarchy("util"));
|
||||
index.addNode(createNameHierarchy("math"));
|
||||
index.addNode(createNameHierarchy("string"));
|
||||
index.addNode(1, NameHierarchy::deserialize("foo1\tvoid\r() const"));
|
||||
index.addNode(2, NameHierarchy::deserialize("foo2\tvoid\r() const"));
|
||||
index.finishSetup();
|
||||
std::vector<SearchResult> results = index.search("oo", 1);
|
||||
|
||||
std::vector<SearchMatch> matches = index.runFuzzySearchAndGetMatches("u");
|
||||
|
||||
TS_ASSERT_EQUALS(1, matches.size());
|
||||
TS_ASSERT_EQUALS("util", matches[0].getFullName());
|
||||
|
||||
TS_ASSERT_EQUALS(1, matches[0].indices.size());
|
||||
TS_ASSERT_EQUALS(0, matches[0].indices[0]);
|
||||
|
||||
matches = index.runFuzzySearchAndGetMatches("");
|
||||
TS_ASSERT_EQUALS(3, matches.size());
|
||||
TS_ASSERT_EQUALS("math", matches[0].getFullName());
|
||||
TS_ASSERT_EQUALS("string", matches[1].getFullName());
|
||||
TS_ASSERT_EQUALS("util", matches[2].getFullName());
|
||||
|
||||
TS_ASSERT_EQUALS(0, matches[0].weight);
|
||||
TS_ASSERT_EQUALS(0, matches[1].weight);
|
||||
TS_ASSERT_EQUALS(0, matches[2].weight);
|
||||
TS_ASSERT_EQUALS(1, results.size());
|
||||
}
|
||||
|
||||
void test_fuzzy_matching_is_case_insensitive()
|
||||
void test_search_index_query_is_case_insensitive()
|
||||
{
|
||||
SearchIndex index;
|
||||
index.addNode(createNameHierarchy("util"));
|
||||
index.addNode(createNameHierarchy("MATH"));
|
||||
index.addNode(1, NameHierarchy::deserialize("foo1\tvoid\r() const"));
|
||||
index.addNode(2, NameHierarchy::deserialize("FOO2\tvoid\r() const"));
|
||||
index.finishSetup();
|
||||
std::vector<SearchResult> results = index.search("oo", 0);
|
||||
|
||||
std::vector<SearchMatch> matches = index.runFuzzySearchAndGetMatches("t");
|
||||
|
||||
TS_ASSERT_EQUALS(2, matches.size());
|
||||
TS_ASSERT_EQUALS("util", matches[0].getFullName());
|
||||
TS_ASSERT_EQUALS("MATH", matches[1].getFullName());
|
||||
|
||||
matches = index.runFuzzySearchAndGetMatches("T");
|
||||
|
||||
TS_ASSERT_EQUALS(2, matches.size());
|
||||
TS_ASSERT_EQUALS("util", matches[0].getFullName());
|
||||
TS_ASSERT_EQUALS("MATH", matches[1].getFullName());
|
||||
TS_ASSERT_EQUALS(2, results.size());
|
||||
}
|
||||
|
||||
void test_fuzzy_matching_wheighs_by_distance_and_alphabet()
|
||||
void test_search_index_rates_higher_on_consecutive_letters()
|
||||
{
|
||||
|
||||
SearchIndex index;
|
||||
index.addNode(createNameHierarchy("util"));
|
||||
index.addNode(createNameHierarchy("math"));
|
||||
index.addNode(createNameHierarchy("string"));
|
||||
index.addNode(1, NameHierarchy::deserialize("oaabbcc\tvoid\r() const"));
|
||||
index.addNode(2, NameHierarchy::deserialize("ocbcabc\tvoid\r() const"));
|
||||
index.finishSetup();
|
||||
std::vector<SearchResult> results = index.search("abc", 0);
|
||||
|
||||
std::vector<SearchMatch> matches = index.runFuzzySearchAndGetMatches("t");
|
||||
|
||||
TS_ASSERT_EQUALS(3, matches.size());
|
||||
TS_ASSERT_EQUALS("string", matches[0].getFullName());
|
||||
TS_ASSERT_EQUALS("util", matches[1].getFullName());
|
||||
TS_ASSERT_EQUALS("math", matches[2].getFullName());
|
||||
|
||||
TS_ASSERT_EQUALS(1, matches[0].indices.size());
|
||||
TS_ASSERT_EQUALS(1, matches[0].indices[0]);
|
||||
|
||||
TS_ASSERT_EQUALS(1, matches[1].indices.size());
|
||||
TS_ASSERT_EQUALS(1, matches[1].indices[0]);
|
||||
|
||||
TS_ASSERT_EQUALS(1, matches[2].indices.size());
|
||||
TS_ASSERT_EQUALS(2, matches[2].indices[0]);
|
||||
}
|
||||
|
||||
void test_fuzzy_matching_wheighs_higher_by_uppercase()
|
||||
{
|
||||
SearchIndex index;
|
||||
index.addNode(createNameHierarchy("uTil"));
|
||||
index.addNode(createNameHierarchy("string"));
|
||||
|
||||
std::vector<SearchMatch> matches = index.runFuzzySearchAndGetMatches("t");
|
||||
|
||||
TS_ASSERT_EQUALS(2, matches.size());
|
||||
TS_ASSERT_EQUALS("uTil", matches[0].getFullName());
|
||||
TS_ASSERT_EQUALS("string", matches[1].getFullName());
|
||||
}
|
||||
|
||||
void test_fuzzy_matching_wheighs_higher_on_consecutive_letters()
|
||||
{
|
||||
SearchIndex index;
|
||||
index.addNode(createNameHierarchy("oaabbcc"));
|
||||
index.addNode(createNameHierarchy("ocbcabc"));
|
||||
|
||||
std::vector<SearchMatch> matches = index.runFuzzySearchAndGetMatches("abc");
|
||||
|
||||
TS_ASSERT_EQUALS(2, matches.size());
|
||||
TS_ASSERT_EQUALS("ocbcabc", matches[0].getFullName());
|
||||
TS_ASSERT_EQUALS("oaabbcc", matches[1].getFullName());
|
||||
}
|
||||
|
||||
void test_fuzzy_matching_in_hierarchy()
|
||||
{
|
||||
SearchIndex index;
|
||||
index.addNode(createNameHierarchy("util::math::ceil"));
|
||||
index.addNode(createNameHierarchy("util::math::floor"));
|
||||
index.addNode(createNameHierarchy("util::string::concat"));
|
||||
|
||||
std::vector<SearchMatch> matches = index.runFuzzySearchAndGetMatches("t");
|
||||
|
||||
TS_ASSERT_EQUALS(6, matches.size());
|
||||
TS_ASSERT_EQUALS("util", matches[0].getFullName());
|
||||
TS_ASSERT_EQUALS("util::math", matches[1].getFullName());
|
||||
TS_ASSERT_EQUALS("util::math::ceil", matches[2].getFullName());
|
||||
TS_ASSERT_EQUALS("util::math::floor", matches[3].getFullName());
|
||||
TS_ASSERT_EQUALS("util::string", matches[4].getFullName());
|
||||
TS_ASSERT_EQUALS("util::string::concat", matches[5].getFullName());
|
||||
|
||||
matches = index.runFuzzySearchAndGetMatches("uml");
|
||||
|
||||
TS_ASSERT_EQUALS(2, matches.size());
|
||||
TS_ASSERT_EQUALS("util::math::ceil", matches[0].getFullName());
|
||||
TS_ASSERT_EQUALS("util::math::floor", matches[1].getFullName());
|
||||
}
|
||||
|
||||
void test_fuzzy_matching_in_hierarchy_respects_collin()
|
||||
{
|
||||
SearchIndex index;
|
||||
index.addNode(createNameHierarchy("util::math::ceil"));
|
||||
index.addNode(createNameHierarchy("util::math::floor"));
|
||||
index.addNode(createNameHierarchy("util::string::concat"));
|
||||
|
||||
std::vector<SearchMatch> matches = index.runFuzzySearchAndGetMatches("u:i");
|
||||
|
||||
TS_ASSERT_EQUALS(3, matches.size());
|
||||
TS_ASSERT_EQUALS("util::string", matches[0].getFullName());
|
||||
TS_ASSERT_EQUALS("util::string::concat", matches[1].getFullName());
|
||||
TS_ASSERT_EQUALS("util::math::ceil", matches[2].getFullName());
|
||||
|
||||
matches = index.runFuzzySearchAndGetMatches("u:t:i");
|
||||
|
||||
TS_ASSERT_EQUALS(1, matches.size());
|
||||
TS_ASSERT_EQUALS("util::math::ceil", matches[0].getFullName());
|
||||
}
|
||||
|
||||
void test_fuzzy_matching_in_hierarchy_weighs_front_letters_higher()
|
||||
{
|
||||
SearchIndex index;
|
||||
index.addNode(createNameHierarchy("abc::dfe::ghi"));
|
||||
index.addNode(createNameHierarchy("abc::hgi"));
|
||||
|
||||
std::vector<SearchMatch> matches = index.runFuzzySearchAndGetMatches("g");
|
||||
|
||||
TS_ASSERT_EQUALS(2, matches.size());
|
||||
TS_ASSERT_EQUALS("abc::dfe::ghi", matches[0].getFullName());
|
||||
TS_ASSERT_EQUALS("abc::hgi", matches[1].getFullName());
|
||||
}
|
||||
|
||||
private:
|
||||
NameHierarchy createNameHierarchy(std::string s) const
|
||||
{
|
||||
NameHierarchy nameHierarchy;
|
||||
for (std::string element: utility::splitToVector(s, "::"))
|
||||
{
|
||||
nameHierarchy.push(std::make_shared<NameElement>(element));
|
||||
}
|
||||
return nameHierarchy;
|
||||
TS_ASSERT_EQUALS(2, results.size());
|
||||
TS_ASSERT_EQUALS("ocbcabc", results[0].text);
|
||||
TS_ASSERT_EQUALS("oaabbcc", results[1].text);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -97,7 +97,6 @@ public:
|
||||
TS_ASSERT_EQUALS(storage.getNodeCount(), 3);
|
||||
TS_ASSERT_EQUALS(storage.getEdgeCount(), 2);
|
||||
TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 4);
|
||||
TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 3);
|
||||
|
||||
std::set<FilePath> files;
|
||||
files.insert(FilePath(m_filePath));
|
||||
@@ -105,8 +104,7 @@ public:
|
||||
|
||||
TS_ASSERT_EQUALS(storage.getNodeCount(), 0);
|
||||
TS_ASSERT_EQUALS(storage.getEdgeCount(), 0);
|
||||
TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 0);
|
||||
TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 0);*/
|
||||
TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 0);*/
|
||||
}
|
||||
|
||||
void test_storage_clears_unreferenced_single_file_data_of_multi_file_storage()
|
||||
@@ -128,7 +126,6 @@ public:
|
||||
//TS_ASSERT_EQUALS(storage.getNodeCount(), 6);
|
||||
//TS_ASSERT_EQUALS(storage.getEdgeCount(), 5);
|
||||
//TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 9);
|
||||
//TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 6);
|
||||
|
||||
//std::set<FilePath> files;
|
||||
//files.insert(FilePath("file.cpp"));
|
||||
@@ -136,8 +133,7 @@ public:
|
||||
|
||||
//TS_ASSERT_EQUALS(storage.getNodeCount(), 3);
|
||||
//TS_ASSERT_EQUALS(storage.getEdgeCount(), 2);
|
||||
//TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 4);
|
||||
//TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 3);
|
||||
//TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 4);*/
|
||||
}
|
||||
|
||||
void test_storage_clears_referenced_single_file_data_of_multi_file_storage()
|
||||
@@ -159,7 +155,6 @@ public:
|
||||
//TS_ASSERT_EQUALS(storage.getNodeCount(), 5);
|
||||
//TS_ASSERT_EQUALS(storage.getEdgeCount(), 5);
|
||||
//TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 9);
|
||||
//TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 5);
|
||||
|
||||
//std::set<FilePath> files;
|
||||
//files.insert(FilePath("file.h"));
|
||||
@@ -168,7 +163,6 @@ public:
|
||||
//TS_ASSERT_EQUALS(storage.getNodeCount(), 4);
|
||||
//TS_ASSERT_EQUALS(storage.getEdgeCount(), 3);
|
||||
//TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 5);
|
||||
//TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 4);
|
||||
}
|
||||
|
||||
void test_storage_clears_multi_file_data_of_multi_file_storage()
|
||||
@@ -190,7 +184,6 @@ public:
|
||||
//TS_ASSERT_EQUALS(storage.getNodeCount(), 5);
|
||||
//TS_ASSERT_EQUALS(storage.getEdgeCount(), 5);
|
||||
//TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 9);
|
||||
//TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 5);
|
||||
|
||||
//std::set<FilePath> filePaths;
|
||||
//filePaths.insert(FilePath("file.cpp"));
|
||||
@@ -200,7 +193,6 @@ public:
|
||||
//TS_ASSERT_EQUALS(storage.getNodeCount(), 0);
|
||||
//TS_ASSERT_EQUALS(storage.getEdgeCount(), 0);
|
||||
//TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 0);
|
||||
//TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 0);
|
||||
}
|
||||
|
||||
void test_storage_finds_and_removes_depending_file_nodes()
|
||||
@@ -248,11 +240,6 @@ private:
|
||||
return getTokenLocationsForTokenIds(tokenIds);
|
||||
}
|
||||
|
||||
//const std::string& getWord(Id wordId) const
|
||||
//{
|
||||
// return getSearchIndex().getWord(wordId);
|
||||
//}
|
||||
|
||||
//const size_t getNodeCount() const
|
||||
//{
|
||||
// return getGraph().getNodeCount();
|
||||
@@ -263,11 +250,6 @@ private:
|
||||
// return getGraph().getEdgeCount();
|
||||
//}
|
||||
|
||||
const SearchIndex& searchIndex() const
|
||||
{
|
||||
return getSearchIndex();
|
||||
}
|
||||
|
||||
Id getEdgeId(Edge::EdgeType type, const NameHierarchy& fromName, const NameHierarchy& toName) const
|
||||
{
|
||||
NameHierarchy from;
|
||||
|
||||
Reference in New Issue
Block a user