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
|
LET'S GET STARTED!\n
|
||||||
\tTo keep things simple just click the "main" symbol below to start the tour.\n
|
\tTo keep things simple just click the "main" symbol below to start the tour.\n
|
||||||
\n
|
\n
|
||||||
[main](); // <- start here\n\n
|
[main\tint\r()](); // <- start here\n\n
|
||||||
</description>
|
</description>
|
||||||
</info>
|
</info>
|
||||||
<source>
|
<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.
|
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
|
Node.cpp WARNING: Cannot change NodeType after it was already set from namespace to class
|
||||||
Edge.cpp ERROR: Nodes are not plain copies.
|
Edge.cpp ERROR: Nodes are not plain copies.
|
||||||
|
|||||||
@@ -134,12 +134,8 @@ add_files(
|
|||||||
|
|
||||||
data/search/SearchIndex.cpp
|
data/search/SearchIndex.cpp
|
||||||
data/search/SearchIndex.h
|
data/search/SearchIndex.h
|
||||||
data/search/SearchNode.cpp
|
|
||||||
data/search/SearchNode.h
|
|
||||||
data/search/SearchMatch.cpp
|
data/search/SearchMatch.cpp
|
||||||
data/search/SearchMatch.h
|
data/search/SearchMatch.h
|
||||||
data/search/SearchResult.cpp
|
|
||||||
data/search/SearchResult.h
|
|
||||||
|
|
||||||
data/type/ArrayModifiedDataType.cpp
|
data/type/ArrayModifiedDataType.cpp
|
||||||
data/type/ArrayModifiedDataType.h
|
data/type/ArrayModifiedDataType.h
|
||||||
|
|||||||
@@ -582,6 +582,7 @@ std::vector<std::string> CodeController::getProjectDescription(TokenLocationFile
|
|||||||
return std::vector<std::string>();
|
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");
|
std::vector<std::string> lines = utility::splitToVector(description, "\\n");
|
||||||
size_t startLineNumber = 4;
|
size_t startLineNumber = 4;
|
||||||
|
|
||||||
@@ -590,6 +591,7 @@ std::vector<std::string> CodeController::getProjectDescription(TokenLocationFile
|
|||||||
std::string line = "\t" + lines[i];
|
std::string line = "\t" + lines[i];
|
||||||
|
|
||||||
line = utility::replace(line, "\\t", "\t");
|
line = utility::replace(line, "\\t", "\t");
|
||||||
|
line = utility::replace(line, "\\r", "\r");
|
||||||
|
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
while (pos != std::string::npos)
|
while (pos != std::string::npos)
|
||||||
@@ -602,21 +604,23 @@ std::vector<std::string> CodeController::getProjectDescription(TokenLocationFile
|
|||||||
break;
|
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)
|
if (tokenId > 0)
|
||||||
{
|
{
|
||||||
line.replace(posA, posB - posA + 1, tokenName);
|
std::string nameString = nameHierarchy.getQualifiedName();
|
||||||
|
line.replace(posA, posB - posA + 1, nameString);
|
||||||
locationFile->addTokenLocation(
|
locationFile->addTokenLocation(
|
||||||
0, tokenId,
|
0, tokenId,
|
||||||
startLineNumber + i, posA + 1,
|
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;
|
lines[i] = line;
|
||||||
|
|||||||
+63
-74
@@ -39,8 +39,9 @@ Version Storage::getVersion() const
|
|||||||
|
|
||||||
bool Storage::init()
|
bool Storage::init()
|
||||||
{
|
{
|
||||||
m_commandIndex.addNode(NameHierarchy(SearchMatch::getCommandName(SearchMatch::COMMAND_ALL)));
|
m_commandIndex.addNode(0, NameHierarchy(SearchMatch::getCommandName(SearchMatch::COMMAND_ALL)));
|
||||||
m_commandIndex.addNode(NameHierarchy(SearchMatch::getCommandName(SearchMatch::COMMAND_ERROR)));
|
m_commandIndex.addNode(0, NameHierarchy(SearchMatch::getCommandName(SearchMatch::COMMAND_ERROR)));
|
||||||
|
m_commandIndex.finishSetup();
|
||||||
|
|
||||||
return m_sqliteStorage.init();
|
return m_sqliteStorage.init();
|
||||||
}
|
}
|
||||||
@@ -54,7 +55,7 @@ void Storage::clear()
|
|||||||
|
|
||||||
void Storage::clearCaches()
|
void Storage::clearCaches()
|
||||||
{
|
{
|
||||||
m_tokenIndex.clear();
|
m_searchIndex.clear();
|
||||||
m_fileNodeIds.clear();
|
m_fileNodeIds.clear();
|
||||||
m_hierarchyCache.clear();
|
m_hierarchyCache.clear();
|
||||||
}
|
}
|
||||||
@@ -135,11 +136,6 @@ std::vector<FileInfo> Storage::getInfoOnAllFiles() const
|
|||||||
return fileInfos;
|
return fileInfos;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SearchIndex& Storage::getSearchIndex() const
|
|
||||||
{
|
|
||||||
return m_tokenIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Storage::logStats() const
|
void Storage::logStats() const
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
@@ -194,17 +190,6 @@ Id Storage::getIdForNodeWithNameHierarchy(const NameHierarchy& nameHierarchy) co
|
|||||||
return m_sqliteStorage.getNodeBySerializedName(NameHierarchy::serialize(nameHierarchy)).id;
|
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(
|
Id Storage::getIdForEdge(
|
||||||
Edge::EdgeType type, const NameHierarchy& fromNameHierarchy, const NameHierarchy& toNameHierarchy
|
Edge::EdgeType type, const NameHierarchy& fromNameHierarchy, const NameHierarchy& toNameHierarchy
|
||||||
) const
|
) const
|
||||||
@@ -231,77 +216,80 @@ Node::NodeType Storage::getNodeTypeForNodeWithId(Id nodeId) const
|
|||||||
|
|
||||||
std::vector<SearchMatch> Storage::getAutocompletionMatches(const std::string& query) 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);
|
SearchMatch match;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_cachedResults = m_tokenIndex.runFuzzySearch(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_cachedQuery = query;
|
if (results[i].elementIds.size() > 0)
|
||||||
|
|
||||||
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())
|
|
||||||
{
|
{
|
||||||
match.searchType = SearchMatch::SEARCH_COMMAND;
|
StorageNode firstNode(0, 0, "", 0);
|
||||||
match.typeName = "command";
|
for (std::set<Id>::const_iterator itElementIds = results[i].elementIds.begin(); itElementIds != results[i].elementIds.end(); itElementIds++)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
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;
|
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;
|
std::vector<SearchMatch> matches;
|
||||||
|
|
||||||
for (Id tokenId : tokenIds)
|
for (Id elementId : elementIds)
|
||||||
{
|
{
|
||||||
SearchMatch match;
|
SearchMatch match;
|
||||||
|
|
||||||
if (m_sqliteStorage.isFile(tokenId))
|
if (m_sqliteStorage.isFile(elementId))
|
||||||
{
|
{
|
||||||
match.nodeType = Node::NODE_FILE;
|
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);
|
match.nodeType = Node::intToType(node.type);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -309,8 +297,9 @@ std::vector<SearchMatch> Storage::getSearchMatchesForTokenIds(const std::vector<
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
match.tokenIds.insert(tokenId);
|
NameHierarchy nameHierarchy = NameHierarchy::deserialize(m_sqliteStorage.getNodeById(elementId).serializedName);
|
||||||
match.nameHierarchy = m_tokenIndex.getNameHierarchyForTokenId(tokenId);
|
match.text = nameHierarchy.getQualifiedName();
|
||||||
|
match.nameHierarchies.push_back(nameHierarchy.getQualifiedName());
|
||||||
match.searchType = SearchMatch::SEARCH_TOKEN;
|
match.searchType = SearchMatch::SEARCH_TOKEN;
|
||||||
|
|
||||||
matches.push_back(match);
|
matches.push_back(match);
|
||||||
@@ -492,10 +481,9 @@ std::vector<Id> Storage::getTokenIdsForMatches(const std::vector<SearchMatch>& m
|
|||||||
std::set<Id> idSet;
|
std::set<Id> idSet;
|
||||||
for (const SearchMatch& match : matches)
|
for (const SearchMatch& match : matches)
|
||||||
{
|
{
|
||||||
SearchNode* searchNode = m_tokenIndex.getNode(match.nameHierarchy);
|
for (size_t i = 0; i < match.nameHierarchies.size(); i++)
|
||||||
if (searchNode)
|
|
||||||
{
|
{
|
||||||
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())
|
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()
|
void Storage::buildHierarchyCache()
|
||||||
|
|||||||
@@ -7,11 +7,11 @@
|
|||||||
#include "utility/file/FilePath.h"
|
#include "utility/file/FilePath.h"
|
||||||
|
|
||||||
#include "data/access/StorageAccess.h"
|
#include "data/access/StorageAccess.h"
|
||||||
#include "data/HierarchyCache.h"
|
|
||||||
#include "data/graph/token_component/TokenComponentAccess.h"
|
#include "data/graph/token_component/TokenComponentAccess.h"
|
||||||
#include "data/location/TokenLocationCollection.h"
|
#include "data/location/TokenLocationCollection.h"
|
||||||
#include "data/parser/ParserClient.h"
|
#include "data/parser/ParserClient.h"
|
||||||
#include "data/search/SearchIndex.h"
|
#include "data/search/SearchIndex.h"
|
||||||
|
#include "data/HierarchyCache.h"
|
||||||
#include "data/SqliteStorage.h"
|
#include "data/SqliteStorage.h"
|
||||||
|
|
||||||
#include "data/parser/ParserClientImpl.h"
|
#include "data/parser/ParserClientImpl.h"
|
||||||
@@ -35,7 +35,6 @@ public:
|
|||||||
void removeUnusedNames();
|
void removeUnusedNames();
|
||||||
|
|
||||||
std::vector<FileInfo> getInfoOnAllFiles() const;
|
std::vector<FileInfo> getInfoOnAllFiles() const;
|
||||||
const SearchIndex& getSearchIndex() const;
|
|
||||||
|
|
||||||
void logStats() const;
|
void logStats() const;
|
||||||
|
|
||||||
@@ -46,7 +45,6 @@ public:
|
|||||||
|
|
||||||
// StorageAccess implementation
|
// StorageAccess implementation
|
||||||
virtual Id getIdForNodeWithNameHierarchy(const NameHierarchy& nameHierarchy) const;
|
virtual Id getIdForNodeWithNameHierarchy(const NameHierarchy& nameHierarchy) const;
|
||||||
virtual Id getIdForNodeWithSearchNameHierarchy(const NameHierarchy& nameHierarchy) const;
|
|
||||||
virtual Id getIdForEdge(
|
virtual Id getIdForEdge(
|
||||||
Edge::EdgeType type, const NameHierarchy& fromNameHierarchy, const NameHierarchy& toNameHierarchy) const;
|
Edge::EdgeType type, const NameHierarchy& fromNameHierarchy, const NameHierarchy& toNameHierarchy) const;
|
||||||
|
|
||||||
@@ -56,7 +54,7 @@ public:
|
|||||||
virtual Node::NodeType getNodeTypeForNodeWithId(Id nodeId) const;
|
virtual Node::NodeType getNodeTypeForNodeWithId(Id nodeId) const;
|
||||||
|
|
||||||
virtual std::vector<SearchMatch> getAutocompletionMatches(const std::string& query) 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> getGraphForAll() const;
|
||||||
virtual std::shared_ptr<Graph> getGraphForActiveTokenIds(const std::vector<Id>& tokenIds, bool activeOnly) 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;
|
void log(std::string type, std::string str, const ParseLocation& location) const;
|
||||||
|
|
||||||
SearchIndex m_tokenIndex;
|
|
||||||
SearchIndex m_commandIndex;
|
SearchIndex m_commandIndex;
|
||||||
|
SearchIndex m_searchIndex;
|
||||||
|
|
||||||
SqliteStorage m_sqliteStorage;
|
SqliteStorage m_sqliteStorage;
|
||||||
|
|
||||||
mutable std::map <FilePath, Id> m_fileNodeIds;
|
mutable std::map <FilePath, Id> m_fileNodeIds;
|
||||||
HierarchyCache m_hierarchyCache;
|
HierarchyCache m_hierarchyCache;
|
||||||
|
|
||||||
mutable SearchResults m_cachedResults;
|
|
||||||
mutable std::string m_cachedQuery;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // STORAGE_H
|
#endif // STORAGE_H
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ public:
|
|||||||
virtual ~StorageAccess();
|
virtual ~StorageAccess();
|
||||||
|
|
||||||
virtual Id getIdForNodeWithNameHierarchy(const NameHierarchy& nameHierarchy) const = 0;
|
virtual Id getIdForNodeWithNameHierarchy(const NameHierarchy& nameHierarchy) const = 0;
|
||||||
virtual Id getIdForNodeWithSearchNameHierarchy(const NameHierarchy& nameHierarchy) const = 0;
|
|
||||||
virtual Id getIdForEdge(
|
virtual Id getIdForEdge(
|
||||||
Edge::EdgeType type, const NameHierarchy& fromNameHierarchy, const NameHierarchy& toNameHierarchy) const = 0;
|
Edge::EdgeType type, const NameHierarchy& fromNameHierarchy, const NameHierarchy& toNameHierarchy) const = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -43,16 +43,6 @@ Id StorageAccessProxy::getIdForNodeWithNameHierarchy(const NameHierarchy& nameHi
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Id StorageAccessProxy::getIdForNodeWithSearchNameHierarchy(const NameHierarchy& nameHierarchy) const
|
|
||||||
{
|
|
||||||
if (hasSubject())
|
|
||||||
{
|
|
||||||
return m_subject->getIdForNodeWithSearchNameHierarchy(nameHierarchy);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Id StorageAccessProxy::getIdForEdge(
|
Id StorageAccessProxy::getIdForEdge(
|
||||||
Edge::EdgeType type, const NameHierarchy& fromNameHierarchy, const NameHierarchy& toNameHierarchy
|
Edge::EdgeType type, const NameHierarchy& fromNameHierarchy, const NameHierarchy& toNameHierarchy
|
||||||
) const {
|
) const {
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ public:
|
|||||||
|
|
||||||
// StorageAccess implementation
|
// StorageAccess implementation
|
||||||
virtual Id getIdForNodeWithNameHierarchy(const NameHierarchy& nameHierarchy) const;
|
virtual Id getIdForNodeWithNameHierarchy(const NameHierarchy& nameHierarchy) const;
|
||||||
virtual Id getIdForNodeWithSearchNameHierarchy(const NameHierarchy& nameHierarchy) const;
|
|
||||||
virtual Id getIdForEdge(
|
virtual Id getIdForEdge(
|
||||||
Edge::EdgeType type, const NameHierarchy& fromNameHierarchy, const NameHierarchy& toNameHierarchy) const;
|
Edge::EdgeType type, const NameHierarchy& fromNameHierarchy, const NameHierarchy& toNameHierarchy) const;
|
||||||
|
|
||||||
|
|||||||
+214
-164
@@ -1,208 +1,258 @@
|
|||||||
#include "data/search/SearchIndex.h"
|
#include "data/search/SearchIndex.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cctype>
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "utility/logging/logging.h"
|
#include "utility/utility.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchIndex::SearchIndex()
|
SearchIndex::SearchIndex()
|
||||||
: m_root(nullptr, DELIMITER, 0)
|
|
||||||
{
|
{
|
||||||
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
SearchIndex::~SearchIndex()
|
SearchIndex::~SearchIndex()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchIndex::clear()
|
void SearchIndex::addNode(Id id, const NameHierarchy& nameHierarchy)
|
||||||
{
|
{
|
||||||
m_root.m_nodes.clear();
|
Node* currentNode = m_root;
|
||||||
m_dictionary.clear();
|
|
||||||
m_tokenIds.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t SearchIndex::getNodeCount() const
|
// 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();
|
||||||
return m_root.getNodeCount() - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t SearchIndex::getCharCount() const
|
while (remaining.size() > 0)
|
||||||
{
|
|
||||||
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++)
|
|
||||||
{
|
{
|
||||||
nameIds.push_back(m_dictionary.getWordId(nameHierarchy[i]->getName()));
|
bool matchingEdgeFound = false;
|
||||||
}
|
// has edge starting with c?
|
||||||
|
for (size_t i = 0; i < currentNode->edges.size(); i++)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
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");
|
populateEdgeGate(m_root->edges[i]);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
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;
|
lowerCaseQuery += tolower(query[i]);
|
||||||
return node->getNameHierarchy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
if (remainingQuery.size() == 0)
|
||||||
{
|
{
|
||||||
return getMatches(runFuzzySearch(query), query);
|
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)
|
if (passesGate)
|
||||||
{
|
{
|
||||||
ostream << "SearchIndex:\n";
|
// consume characters for edge
|
||||||
ostream << &index.m_root;
|
const std::string& edgeString = currentEdge->s;
|
||||||
return ostream;
|
|
||||||
|
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
|
#ifndef SEARCH_INDEX_H
|
||||||
#define SEARCH_INDEX_H
|
#define SEARCH_INDEX_H
|
||||||
|
|
||||||
#include <ostream>
|
#include <map>
|
||||||
#include <set>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
#include "utility/text/Dictionary.h"
|
#include <string>
|
||||||
#include "utility/types.h"
|
#include <unordered_set>
|
||||||
|
|
||||||
#include "data/name/NameHierarchy.h"
|
#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
|
class SearchIndex
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static std::vector<SearchMatch> getMatches(const SearchResults& searchResults, const std::string& query);
|
|
||||||
|
|
||||||
SearchIndex();
|
SearchIndex();
|
||||||
virtual ~SearchIndex();
|
virtual ~SearchIndex();
|
||||||
|
|
||||||
|
void addNode(Id id, const NameHierarchy& nameHierarchy);
|
||||||
|
void finishSetup();
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
size_t getNodeCount() const;
|
// maxResultCount == 0 means "no restriction".
|
||||||
size_t getCharCount() const;
|
std::vector<SearchResult> search(const std::string& query, size_t maxResultCount) 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;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SearchNode m_root;
|
struct Node;
|
||||||
Dictionary m_dictionary;
|
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
|
#endif // SEARCH_INDEX_H
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ std::string SearchMatch::searchMatchesToString(const std::vector<SearchMatch>& m
|
|||||||
SearchMatch SearchMatch::createCommand(CommandType type)
|
SearchMatch SearchMatch::createCommand(CommandType type)
|
||||||
{
|
{
|
||||||
SearchMatch match;
|
SearchMatch match;
|
||||||
match.nameHierarchy = NameHierarchy(getCommandName(type));
|
match.text = getCommandName(type);
|
||||||
match.typeName = "command";
|
match.typeName = "command";
|
||||||
match.searchType = SEARCH_COMMAND;
|
match.searchType = SEARCH_COMMAND;
|
||||||
return match;
|
return match;
|
||||||
@@ -74,7 +74,7 @@ SearchMatch::SearchMatch()
|
|||||||
}
|
}
|
||||||
|
|
||||||
SearchMatch::SearchMatch(const std::string& query)
|
SearchMatch::SearchMatch(const std::string& query)
|
||||||
: nameHierarchy(query)
|
: text(query)
|
||||||
, typeName("")
|
, typeName("")
|
||||||
, searchType(SEARCH_NONE)
|
, searchType(SEARCH_NONE)
|
||||||
{
|
{
|
||||||
@@ -87,7 +87,7 @@ bool SearchMatch::isValid() const
|
|||||||
|
|
||||||
void SearchMatch::print(std::ostream& ostream) 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;
|
size_t i = 0;
|
||||||
for (size_t index : indices)
|
for (size_t index : indices)
|
||||||
{
|
{
|
||||||
@@ -104,7 +104,7 @@ void SearchMatch::print(std::ostream& ostream) const
|
|||||||
|
|
||||||
std::string SearchMatch::getFullName() const
|
std::string SearchMatch::getFullName() const
|
||||||
{
|
{
|
||||||
return nameHierarchy.getQualifiedName();
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SearchMatch::getNodeTypeAsString() const
|
std::string SearchMatch::getNodeTypeAsString() const
|
||||||
|
|||||||
@@ -44,16 +44,13 @@ struct SearchMatch
|
|||||||
std::string getNodeTypeAsString() const;
|
std::string getNodeTypeAsString() const;
|
||||||
std::string getSearchTypeName() const;
|
std::string getSearchTypeName() const;
|
||||||
|
|
||||||
NameHierarchy nameHierarchy;
|
std::string text;
|
||||||
std::string typeName;
|
std::string typeName;
|
||||||
|
|
||||||
Node::NodeType nodeType;
|
Node::NodeType nodeType;
|
||||||
SearchType searchType;
|
SearchType searchType;
|
||||||
|
|
||||||
std::set<Id> tokenIds;
|
|
||||||
|
|
||||||
std::vector<size_t> indices;
|
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 <deque>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
#include "boost/date_time/posix_time/posix_time.hpp"
|
#include "boost/date_time/posix_time/posix_time.hpp"
|
||||||
|
|
||||||
@@ -30,6 +31,9 @@ namespace utility
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
void append(std::set<T>& a, const std::set<T>& b);
|
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>
|
template<typename T>
|
||||||
std::vector<T> toVector(const std::deque<T>& d);
|
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());
|
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>
|
template<typename T>
|
||||||
std::vector<T> utility::toVector(const std::deque<T>& d)
|
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())
|
if (m_matches.size())
|
||||||
{
|
{
|
||||||
@@ -415,7 +415,7 @@ void QtSmartSearchBox::onTextEdited(const QString& text)
|
|||||||
layoutElements();
|
layoutElements();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match.nameHierarchy.size() || m_elements.size())
|
if (match.text.size() || m_elements.size())
|
||||||
{
|
{
|
||||||
requestAutoCompletions();
|
requestAutoCompletions();
|
||||||
}
|
}
|
||||||
@@ -446,7 +446,7 @@ void QtSmartSearchBox::onAutocompletionActivated(const SearchMatch& match)
|
|||||||
{
|
{
|
||||||
addMatchAndUpdate(match);
|
addMatchAndUpdate(match);
|
||||||
|
|
||||||
if (match.nameHierarchy.size())
|
if (match.text.size())
|
||||||
{
|
{
|
||||||
search();
|
search();
|
||||||
}
|
}
|
||||||
@@ -516,7 +516,7 @@ void QtSmartSearchBox::moveCursorTo(int target)
|
|||||||
|
|
||||||
void QtSmartSearchBox::addMatch(const SearchMatch& match)
|
void QtSmartSearchBox::addMatch(const SearchMatch& match)
|
||||||
{
|
{
|
||||||
if (!match.nameHierarchy.size())
|
if (!match.text.size())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -543,7 +543,7 @@ void QtSmartSearchBox::addMatch(const SearchMatch& match)
|
|||||||
|
|
||||||
void QtSmartSearchBox::addMatchAndUpdate(const SearchMatch& match)
|
void QtSmartSearchBox::addMatchAndUpdate(const SearchMatch& match)
|
||||||
{
|
{
|
||||||
if (match.nameHierarchy.size())
|
if (match.text.size())
|
||||||
{
|
{
|
||||||
m_oldText.clear();
|
m_oldText.clear();
|
||||||
clearLineEdit();
|
clearLineEdit();
|
||||||
|
|||||||
+52
-259
@@ -3,302 +3,95 @@
|
|||||||
#include "utility/utilityString.h"
|
#include "utility/utilityString.h"
|
||||||
|
|
||||||
#include "data/search/SearchIndex.h"
|
#include "data/search/SearchIndex.h"
|
||||||
#include "data/search/SearchMatch.h"
|
|
||||||
|
|
||||||
class SearchIndexTestSuite : public CxxTest::TestSuite
|
class SearchIndexTestSuite : public CxxTest::TestSuite
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void test_add_node()
|
|
||||||
|
void test_search_index_finds_id_of_element_added()
|
||||||
{
|
{
|
||||||
SearchIndex index;
|
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(1, results.size());
|
||||||
TS_ASSERT_EQUALS("util", node->getName());
|
TS_ASSERT_EQUALS(1, results[0].elementIds.size());
|
||||||
TS_ASSERT_EQUALS("util", node->getFullName());
|
TS_ASSERT_DIFFERS(results[0].elementIds.end(), results[0].elementIds.find(1));
|
||||||
|
|
||||||
TS_ASSERT(node->getNameId());
|
|
||||||
TS_ASSERT(!node->getFirstTokenId());
|
|
||||||
TS_ASSERT(node->getParent());
|
|
||||||
TS_ASSERT(!node->getParent()->getNameId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_get_node()
|
void test_search_index_finds_correct_indices_for_query()
|
||||||
{
|
{
|
||||||
SearchIndex index;
|
SearchIndex index;
|
||||||
index.addNode(createNameHierarchy("util"));
|
index.addNode(1, NameHierarchy::deserialize("foo\tvoid\r() const"));
|
||||||
SearchNode* node = index.getNode("util");
|
index.finishSetup();
|
||||||
|
std::vector<SearchResult> results = index.search("oo", 0);
|
||||||
|
|
||||||
TS_ASSERT(node);
|
TS_ASSERT_EQUALS(1, results.size());
|
||||||
TS_ASSERT_EQUALS("util", node->getName());
|
TS_ASSERT_EQUALS(2, results[0].indices.size());
|
||||||
TS_ASSERT_EQUALS("util", node->getFullName());
|
TS_ASSERT_EQUALS(1, results[0].indices[0]);
|
||||||
|
TS_ASSERT_EQUALS(2, results[0].indices[1]);
|
||||||
TS_ASSERT(node->getNameId());
|
|
||||||
TS_ASSERT(!node->getFirstTokenId());
|
|
||||||
TS_ASSERT(node->getParent());
|
|
||||||
TS_ASSERT(!node->getParent()->getNameId());
|
|
||||||
|
|
||||||
node = index.getNode("math");
|
|
||||||
TS_ASSERT(!node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_add_hierarchy_node()
|
void test_search_index_finds_ids_for_ambiguous_query()
|
||||||
{
|
{
|
||||||
SearchIndex index;
|
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(2, results.size());
|
||||||
TS_ASSERT_EQUALS("pow", node->getName());
|
TS_ASSERT_EQUALS(1, results[0].elementIds.size());
|
||||||
TS_ASSERT_EQUALS("util::math::pow", node->getFullName());
|
TS_ASSERT_DIFFERS(results[0].elementIds.end(), results[0].elementIds.find(1));
|
||||||
|
TS_ASSERT_EQUALS(1, results[1].elementIds.size());
|
||||||
TS_ASSERT(node->getNameId());
|
TS_ASSERT_DIFFERS(results[1].elementIds.end(), results[1].elementIds.find(2));
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_reuse_hierarchy_node()
|
void test_search_index_does_not_find_anything_after_clear()
|
||||||
{
|
{
|
||||||
SearchIndex index;
|
SearchIndex index;
|
||||||
SearchNode* node1 = index.addNode(createNameHierarchy("math::pow"));
|
index.addNode(1, NameHierarchy::deserialize("foo\tvoid\r() const"));
|
||||||
SearchNode* node2 = index.addNode(createNameHierarchy("math::floor"));
|
index.finishSetup();
|
||||||
|
|
||||||
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.clear();
|
index.clear();
|
||||||
|
std::vector<SearchResult> results = index.search("oo", 0);
|
||||||
|
|
||||||
TS_ASSERT(!index.getNode("math"));
|
TS_ASSERT_EQUALS(0, results.size());
|
||||||
TS_ASSERT(!index.getNode("string"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_fuzzy_matching()
|
void test_search_index_does_not_find_all_results_when_max_amount_is_limited()
|
||||||
{
|
{
|
||||||
SearchIndex index;
|
SearchIndex index;
|
||||||
index.addNode(createNameHierarchy("util"));
|
index.addNode(1, NameHierarchy::deserialize("foo1\tvoid\r() const"));
|
||||||
index.addNode(createNameHierarchy("math"));
|
index.addNode(2, NameHierarchy::deserialize("foo2\tvoid\r() const"));
|
||||||
index.addNode(createNameHierarchy("string"));
|
index.finishSetup();
|
||||||
|
std::vector<SearchResult> results = index.search("oo", 1);
|
||||||
|
|
||||||
std::vector<SearchMatch> matches = index.runFuzzySearchAndGetMatches("u");
|
TS_ASSERT_EQUALS(1, results.size());
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_fuzzy_matching_is_case_insensitive()
|
void test_search_index_query_is_case_insensitive()
|
||||||
{
|
{
|
||||||
SearchIndex index;
|
SearchIndex index;
|
||||||
index.addNode(createNameHierarchy("util"));
|
index.addNode(1, NameHierarchy::deserialize("foo1\tvoid\r() const"));
|
||||||
index.addNode(createNameHierarchy("MATH"));
|
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, results.size());
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_fuzzy_matching_wheighs_by_distance_and_alphabet()
|
void test_search_index_rates_higher_on_consecutive_letters()
|
||||||
{
|
{
|
||||||
|
|
||||||
SearchIndex index;
|
SearchIndex index;
|
||||||
index.addNode(createNameHierarchy("util"));
|
index.addNode(1, NameHierarchy::deserialize("oaabbcc\tvoid\r() const"));
|
||||||
index.addNode(createNameHierarchy("math"));
|
index.addNode(2, NameHierarchy::deserialize("ocbcabc\tvoid\r() const"));
|
||||||
index.addNode(createNameHierarchy("string"));
|
index.finishSetup();
|
||||||
|
std::vector<SearchResult> results = index.search("abc", 0);
|
||||||
|
|
||||||
std::vector<SearchMatch> matches = index.runFuzzySearchAndGetMatches("t");
|
TS_ASSERT_EQUALS(2, results.size());
|
||||||
|
TS_ASSERT_EQUALS("ocbcabc", results[0].text);
|
||||||
TS_ASSERT_EQUALS(3, matches.size());
|
TS_ASSERT_EQUALS("oaabbcc", results[1].text);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -97,7 +97,6 @@ public:
|
|||||||
TS_ASSERT_EQUALS(storage.getNodeCount(), 3);
|
TS_ASSERT_EQUALS(storage.getNodeCount(), 3);
|
||||||
TS_ASSERT_EQUALS(storage.getEdgeCount(), 2);
|
TS_ASSERT_EQUALS(storage.getEdgeCount(), 2);
|
||||||
TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 4);
|
TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 4);
|
||||||
TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 3);
|
|
||||||
|
|
||||||
std::set<FilePath> files;
|
std::set<FilePath> files;
|
||||||
files.insert(FilePath(m_filePath));
|
files.insert(FilePath(m_filePath));
|
||||||
@@ -105,8 +104,7 @@ public:
|
|||||||
|
|
||||||
TS_ASSERT_EQUALS(storage.getNodeCount(), 0);
|
TS_ASSERT_EQUALS(storage.getNodeCount(), 0);
|
||||||
TS_ASSERT_EQUALS(storage.getEdgeCount(), 0);
|
TS_ASSERT_EQUALS(storage.getEdgeCount(), 0);
|
||||||
TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 0);
|
TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 0);*/
|
||||||
TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 0);*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_storage_clears_unreferenced_single_file_data_of_multi_file_storage()
|
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.getNodeCount(), 6);
|
||||||
//TS_ASSERT_EQUALS(storage.getEdgeCount(), 5);
|
//TS_ASSERT_EQUALS(storage.getEdgeCount(), 5);
|
||||||
//TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 9);
|
//TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 9);
|
||||||
//TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 6);
|
|
||||||
|
|
||||||
//std::set<FilePath> files;
|
//std::set<FilePath> files;
|
||||||
//files.insert(FilePath("file.cpp"));
|
//files.insert(FilePath("file.cpp"));
|
||||||
@@ -136,8 +133,7 @@ public:
|
|||||||
|
|
||||||
//TS_ASSERT_EQUALS(storage.getNodeCount(), 3);
|
//TS_ASSERT_EQUALS(storage.getNodeCount(), 3);
|
||||||
//TS_ASSERT_EQUALS(storage.getEdgeCount(), 2);
|
//TS_ASSERT_EQUALS(storage.getEdgeCount(), 2);
|
||||||
//TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 4);
|
//TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 4);*/
|
||||||
//TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_storage_clears_referenced_single_file_data_of_multi_file_storage()
|
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.getNodeCount(), 5);
|
||||||
//TS_ASSERT_EQUALS(storage.getEdgeCount(), 5);
|
//TS_ASSERT_EQUALS(storage.getEdgeCount(), 5);
|
||||||
//TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 9);
|
//TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 9);
|
||||||
//TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 5);
|
|
||||||
|
|
||||||
//std::set<FilePath> files;
|
//std::set<FilePath> files;
|
||||||
//files.insert(FilePath("file.h"));
|
//files.insert(FilePath("file.h"));
|
||||||
@@ -168,7 +163,6 @@ public:
|
|||||||
//TS_ASSERT_EQUALS(storage.getNodeCount(), 4);
|
//TS_ASSERT_EQUALS(storage.getNodeCount(), 4);
|
||||||
//TS_ASSERT_EQUALS(storage.getEdgeCount(), 3);
|
//TS_ASSERT_EQUALS(storage.getEdgeCount(), 3);
|
||||||
//TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 5);
|
//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()
|
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.getNodeCount(), 5);
|
||||||
//TS_ASSERT_EQUALS(storage.getEdgeCount(), 5);
|
//TS_ASSERT_EQUALS(storage.getEdgeCount(), 5);
|
||||||
//TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 9);
|
//TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 9);
|
||||||
//TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 5);
|
|
||||||
|
|
||||||
//std::set<FilePath> filePaths;
|
//std::set<FilePath> filePaths;
|
||||||
//filePaths.insert(FilePath("file.cpp"));
|
//filePaths.insert(FilePath("file.cpp"));
|
||||||
@@ -200,7 +193,6 @@ public:
|
|||||||
//TS_ASSERT_EQUALS(storage.getNodeCount(), 0);
|
//TS_ASSERT_EQUALS(storage.getNodeCount(), 0);
|
||||||
//TS_ASSERT_EQUALS(storage.getEdgeCount(), 0);
|
//TS_ASSERT_EQUALS(storage.getEdgeCount(), 0);
|
||||||
//TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 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()
|
void test_storage_finds_and_removes_depending_file_nodes()
|
||||||
@@ -248,11 +240,6 @@ private:
|
|||||||
return getTokenLocationsForTokenIds(tokenIds);
|
return getTokenLocationsForTokenIds(tokenIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
//const std::string& getWord(Id wordId) const
|
|
||||||
//{
|
|
||||||
// return getSearchIndex().getWord(wordId);
|
|
||||||
//}
|
|
||||||
|
|
||||||
//const size_t getNodeCount() const
|
//const size_t getNodeCount() const
|
||||||
//{
|
//{
|
||||||
// return getGraph().getNodeCount();
|
// return getGraph().getNodeCount();
|
||||||
@@ -263,11 +250,6 @@ private:
|
|||||||
// return getGraph().getEdgeCount();
|
// return getGraph().getEdgeCount();
|
||||||
//}
|
//}
|
||||||
|
|
||||||
const SearchIndex& searchIndex() const
|
|
||||||
{
|
|
||||||
return getSearchIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
Id getEdgeId(Edge::EdgeType type, const NameHierarchy& fromName, const NameHierarchy& toName) const
|
Id getEdgeId(Edge::EdgeType type, const NameHierarchy& fromName, const NameHierarchy& toName) const
|
||||||
{
|
{
|
||||||
NameHierarchy from;
|
NameHierarchy from;
|
||||||
|
|||||||
Reference in New Issue
Block a user