logic: Add node type filtering to SearchIndex to avoid low or no results for filters

This commit is contained in:
Eberhard Graether
2017-09-07 01:40:20 +02:00
parent a9ca7f1223
commit 3c8cd26846
4 changed files with 67 additions and 66 deletions
+34 -32
View File
@@ -16,9 +16,9 @@ SearchIndex::~SearchIndex()
{
}
void SearchIndex::addNode(Id id, const std::string& name)
void SearchIndex::addNode(Id id, const std::string& name, Node::NodeTypeMask type)
{
Node* currentNode = m_root;
SearchNode* currentNode = m_root;
std::string remaining = name;
while (remaining.size() > 0)
@@ -26,7 +26,7 @@ void SearchIndex::addNode(Id id, const std::string& name)
auto it = currentNode->edges.find(remaining[0]);
if (it != currentNode->edges.end())
{
Edge* currentEdge = it->second;
SearchEdge* currentEdge = it->second;
const std::string& edgeString = currentEdge->s;
size_t matchCount = 1;
@@ -42,9 +42,9 @@ void SearchIndex::addNode(Id id, const std::string& name)
if (matchCount < edgeString.size())
{
// split current edge
std::shared_ptr<Node> n = std::make_shared<Node>();
std::shared_ptr<SearchNode> n = std::make_shared<SearchNode>();
m_nodes.push_back(n);
std::shared_ptr<Edge> e = std::make_shared<Edge>();
std::shared_ptr<SearchEdge> e = std::make_shared<SearchEdge>();
m_edges.push_back(e);
e->s = edgeString.substr(matchCount);
@@ -61,9 +61,9 @@ void SearchIndex::addNode(Id id, const std::string& name)
}
else
{
std::shared_ptr<Node> n = std::make_shared<Node>();
std::shared_ptr<SearchNode> n = std::make_shared<SearchNode>();
m_nodes.push_back(n);
std::shared_ptr<Edge> e = std::make_shared<Edge>();
std::shared_ptr<SearchEdge> e = std::make_shared<SearchEdge>();
m_edges.push_back(e);
e->s = remaining;
@@ -77,6 +77,7 @@ void SearchIndex::addNode(Id id, const std::string& name)
}
currentNode->elementIds.insert(id);
currentNode->mask |= type;
}
void SearchIndex::finishSetup()
@@ -92,24 +93,24 @@ void SearchIndex::clear()
m_nodes.clear();
m_edges.clear();
std::shared_ptr<Node> n = std::make_shared<Node>();
std::shared_ptr<SearchNode> n = std::make_shared<SearchNode>();
m_nodes.push_back(n);
m_root = n.get();
}
std::vector<SearchResult> SearchIndex::search(
const std::string& query, size_t maxResultCount, size_t maxBestScoredLength) const
const std::string& query, Node::NodeTypeMask filter, size_t maxResultCount, size_t maxBestScoredLength) const
{
// find paths containing query
Path startPath;
SearchPath startPath;
startPath.node = m_root;
std::vector<Path> paths;
searchRecursive(startPath, utility::toLowerCase(query), &paths);
std::vector<SearchPath> paths;
searchRecursive(startPath, utility::toLowerCase(query), filter, &paths);
// create scored search results
std::multiset<SearchResult> searchResults = createScoredResults(paths, maxResultCount * 3);
std::multiset<SearchResult> searchResults = createScoredResults(paths, filter, maxResultCount * 3);
// find best scores
std::map<std::string, SearchResult> scoresCache;
@@ -130,12 +131,12 @@ std::vector<SearchResult> SearchIndex::search(
return std::vector<SearchResult>(bestResults.begin(), it);
}
void SearchIndex::populateEdgeGate(Edge* e)
void SearchIndex::populateEdgeGate(SearchEdge* e)
{
Node* target = e->target;
SearchNode* target = e->target;
for (auto p : target->edges)
{
Edge* targetEdge = p.second;
SearchEdge* targetEdge = p.second;
populateEdgeGate(targetEdge);
utility::append(e->gate, targetEdge->gate);
}
@@ -146,9 +147,9 @@ void SearchIndex::populateEdgeGate(Edge* e)
}
void SearchIndex::searchRecursive(
const Path& path, const std::string& remainingQuery, std::vector<SearchIndex::Path>* results) const
const SearchPath& path, const std::string& remainingQuery, Node::NodeTypeMask filter, std::vector<SearchIndex::SearchPath>* results) const
{
if (remainingQuery.size() == 0)
if (remainingQuery.size() == 0 && (!filter || (path.node->mask & filter)))
{
results->push_back(path);
return;
@@ -156,7 +157,7 @@ void SearchIndex::searchRecursive(
for (auto p : path.node->edges)
{
const Edge* currentEdge = p.second;
const SearchEdge* currentEdge = p.second;
// test if s passes the edge's gate.
bool passesGate = true;
@@ -185,45 +186,46 @@ void SearchIndex::searchRecursive(
}
}
Path currentPath;
SearchPath currentPath;
currentPath.node = currentEdge->target;
currentPath.indices = indices;
currentPath.text = path.text + edgeString;
searchRecursive(currentPath, remainingQuery.substr(j), results);
searchRecursive(currentPath, remainingQuery.substr(j), filter, results);
}
}
}
std::multiset<SearchResult> SearchIndex::createScoredResults(const std::vector<Path>& paths, size_t maxResultCount) const
std::multiset<SearchResult> SearchIndex::createScoredResults(
const std::vector<SearchPath>& paths, Node::NodeTypeMask filter, size_t maxResultCount) const
{
// score and order initial paths
std::multiset<std::pair<int, Path>, bool(*)(const std::pair<int, Path>&, const std::pair<int, Path>&)> scoredPaths(
[](const std::pair<int, Path>& a, const std::pair<int, Path>& b)
std::multiset<std::pair<int, SearchPath>, bool(*)(const std::pair<int, SearchPath>&, const std::pair<int, SearchPath>&)> scoredPaths(
[](const std::pair<int, SearchPath>& a, const std::pair<int, SearchPath>& b)
{
return a.first > b.first;
}
);
for (const Path& path : paths)
for (const SearchPath& path : paths)
{
scoredPaths.insert(std::make_pair(scoreText(path.text, path.indices), path));
}
// score paths and subpaths
std::multiset<SearchResult> searchResults;
for (const std::pair<int, Path>& p : scoredPaths)
for (const std::pair<int, SearchPath>& p : scoredPaths)
{
std::vector<Path> currentPaths;
std::vector<SearchPath> currentPaths;
currentPaths.push_back(p.second);
while (currentPaths.size())
{
std::vector<Path> nextPaths;
std::vector<SearchPath> nextPaths;
for (const Path& path : currentPaths)
for (const SearchPath& path : currentPaths)
{
if (path.node->elementIds.size())
if (path.node->elementIds.size() && (!filter || (path.node->mask & filter)))
{
SearchResult result;
result.text = path.text;
@@ -240,8 +242,8 @@ std::multiset<SearchResult> SearchIndex::createScoredResults(const std::vector<P
for (auto p : path.node->edges)
{
const Edge* edge = p.second;
Path nextPath;
const SearchEdge* edge = p.second;
SearchPath nextPath;
nextPath.indices = path.indices;
nextPath.node = edge->target;
nextPath.text = path.text + edge->s;
+19 -16
View File
@@ -9,6 +9,7 @@
#include <unordered_set>
#include "utility/types.h"
#include "data/graph/Node.h"
struct SearchResult
{
@@ -29,41 +30,43 @@ public:
SearchIndex();
virtual ~SearchIndex();
void addNode(Id id, const std::string& name);
void addNode(Id id, const std::string& name, Node::NodeTypeMask type = 0);
void finishSetup();
void clear();
// maxResultCount == 0 means "no restriction".
std::vector<SearchResult> search(const std::string& query, size_t maxResultCount, size_t maxBestScoredLength = 0) const;
std::vector<SearchResult> search(const std::string& query, Node::NodeTypeMask filter, size_t maxResultCount, size_t maxBestScoredLength = 0) const;
private:
struct Node;
struct Edge;
struct SearchEdge;
struct Node
struct SearchNode
{
std::set<Id> elementIds;
std::map<char, Edge*> edges;
Node::NodeTypeMask mask = 0;
std::map<char, SearchEdge*> edges;
};
struct Edge
struct SearchEdge
{
Node* target;
SearchNode* target;
std::string s;
std::unordered_set<char> gate;
};
struct Path
struct SearchPath
{
std::string text;
std::vector<size_t> indices;
Node* node;
SearchNode* node;
};
void populateEdgeGate(Edge* e);
void searchRecursive(const Path& path, const std::string& remainingQuery, std::vector<SearchIndex::Path>* results) const;
void populateEdgeGate(SearchEdge* e);
void searchRecursive(const SearchPath& path, const std::string& remainingQuery, Node::NodeTypeMask filter,
std::vector<SearchIndex::SearchPath>* results) const;
std::multiset<SearchResult> createScoredResults(const std::vector<Path>& paths, size_t maxResultCount) const;
std::multiset<SearchResult> createScoredResults(
const std::vector<SearchPath>& paths, Node::NodeTypeMask filter, size_t maxResultCount) const;
static SearchResult bestScoredResult(
SearchResult result, std::map<std::string, SearchResult>* scoresCache, size_t maxBestScoredLength);
@@ -81,9 +84,9 @@ public:
size_t maxBestScoredLength);
private:
std::vector<std::shared_ptr<Node>> m_nodes;
std::vector<std::shared_ptr<Edge>> m_edges;
Node* m_root;
std::vector<std::shared_ptr<SearchNode>> m_nodes;
std::vector<std::shared_ptr<SearchEdge>> m_edges;
SearchNode* m_root;
};
#endif // SEARCH_INDEX_H
+7 -11
View File
@@ -627,7 +627,7 @@ std::vector<SearchMatch> PersistentStorage::getAutocompletionSymbolMatches(
const std::string& query, Node::NodeTypeMask filter, size_t maxResultsCount) const
{
// search in indices
std::vector<SearchResult> results = m_symbolIndex.search(query, maxResultsCount, maxResultsCount);
std::vector<SearchResult> results = m_symbolIndex.search(query, filter, maxResultsCount, maxResultsCount);
// fetch StorageNodes for node ids
std::map<Id, StorageNode> storageNodeMap;
@@ -676,11 +676,6 @@ std::vector<SearchMatch> PersistentStorage::getAutocompletionSymbolMatches(
}
}
if (filter && !(filter & Node::intToType(firstNode->type)))
{
continue;
}
match.name = result.text;
match.text = result.text;
@@ -714,7 +709,7 @@ std::vector<SearchMatch> PersistentStorage::getAutocompletionSymbolMatches(
std::vector<SearchMatch> PersistentStorage::getAutocompletionFileMatches(const std::string& query, size_t maxResultsCount) const
{
std::vector<SearchResult> results = m_fileIndex.search(query, maxResultsCount);
std::vector<SearchResult> results = m_fileIndex.search(query, Node::NODE_FILE, maxResultsCount);
// create SearchMatches
std::vector<SearchMatch> matches;
@@ -749,7 +744,7 @@ std::vector<SearchMatch> PersistentStorage::getAutocompletionCommandMatches(
const std::string& query, Node::NodeTypeMask filter) const
{
// search in indices
std::vector<SearchResult> results = m_commandIndex.search(query, 0);
std::vector<SearchResult> results = m_commandIndex.search(query, 0, 0);
// create SearchMatches
std::vector<SearchMatch> matches;
@@ -2467,7 +2462,8 @@ void PersistentStorage::buildSearchIndex()
for (StorageNode& node : m_sqliteIndexStorage.getAll<StorageNode>())
{
if (Node::intToType(node.type) == Node::NODE_FILE)
Node::NodeType type = Node::intToType(node.type);
if (type == Node::NODE_FILE)
{
auto it = m_fileNodePaths.find(node.id);
if (it != m_fileNodePaths.end())
@@ -2479,7 +2475,7 @@ void PersistentStorage::buildSearchIndex()
filePath = filePath.relativeTo(dbPath);
}
m_fileIndex.addNode(node.id, filePath.str());
m_fileIndex.addNode(node.id, filePath.str(), type);
}
}
else
@@ -2499,7 +2495,7 @@ void PersistentStorage::buildSearchIndex()
name = utility::replaceBetween(name, '<', '>', "..");
}
m_symbolIndex.addNode(node.id, name);
m_symbolIndex.addNode(node.id, name, type);
}
}
}
+7 -7
View File
@@ -12,7 +12,7 @@ public:
SearchIndex index;
index.addNode(1, NameHierarchy::deserialize("::\tmfoo\tsvoid\tp() const").getQualifiedName());
index.finishSetup();
std::vector<SearchResult> results = index.search("oo", 0);
std::vector<SearchResult> results = index.search("oo", 0, 0);
TS_ASSERT_EQUALS(1, results.size());
TS_ASSERT_EQUALS(1, results[0].elementIds.size());
@@ -24,7 +24,7 @@ public:
SearchIndex index;
index.addNode(1, NameHierarchy::deserialize("::\tmfoo\tsvoid\tp() const").getQualifiedName());
index.finishSetup();
std::vector<SearchResult> results = index.search("oo", 0);
std::vector<SearchResult> results = index.search("oo", 0, 0);
TS_ASSERT_EQUALS(1, results.size());
TS_ASSERT_EQUALS(2, results[0].indices.size());
@@ -38,7 +38,7 @@ public:
index.addNode(1, NameHierarchy::deserialize("::\tmfor\tsvoid\tp() const").getQualifiedName());
index.addNode(2, NameHierarchy::deserialize("::\tmfos\tsvoid\tp() const").getQualifiedName());
index.finishSetup();
std::vector<SearchResult> results = index.search("fo", 0);
std::vector<SearchResult> results = index.search("fo", 0, 0);
TS_ASSERT_EQUALS(2, results.size());
TS_ASSERT_EQUALS(1, results[0].elementIds.size());
@@ -53,7 +53,7 @@ public:
index.addNode(1, NameHierarchy::deserialize("::\tmfoo\tsvoid\tp() const").getQualifiedName());
index.finishSetup();
index.clear();
std::vector<SearchResult> results = index.search("oo", 0);
std::vector<SearchResult> results = index.search("oo", 0, 0);
TS_ASSERT_EQUALS(0, results.size());
}
@@ -64,7 +64,7 @@ public:
index.addNode(1, NameHierarchy::deserialize("::\tmfoo1\tsvoid\tp() const").getQualifiedName());
index.addNode(2, NameHierarchy::deserialize("::\tmfoo2\tsvoid\tp() const").getQualifiedName());
index.finishSetup();
std::vector<SearchResult> results = index.search("oo", 1);
std::vector<SearchResult> results = index.search("oo", 0, 1);
TS_ASSERT_EQUALS(1, results.size());
}
@@ -75,7 +75,7 @@ public:
index.addNode(1, NameHierarchy::deserialize("::\tmfoo1\tsvoid\tp() const").getQualifiedName());
index.addNode(2, NameHierarchy::deserialize("::\tmFOO2\tsvoid\tp() const").getQualifiedName());
index.finishSetup();
std::vector<SearchResult> results = index.search("oo", 0);
std::vector<SearchResult> results = index.search("oo", 0, 0);
TS_ASSERT_EQUALS(2, results.size());
}
@@ -87,7 +87,7 @@ public:
index.addNode(1, NameHierarchy::deserialize("::\tmoaabbcc\tsvoid\tp() const").getQualifiedName());
index.addNode(2, NameHierarchy::deserialize("::\tmocbcabc\tsvoid\tp() const").getQualifiedName());
index.finishSetup();
std::vector<SearchResult> results = index.search("abc", 0);
std::vector<SearchResult> results = index.search("abc", 0, 0);
TS_ASSERT_EQUALS(2, results.size());
TS_ASSERT_EQUALS("ocbcabc", results[0].text);