sorting search results occurences in the note title

This commit is contained in:
zadam 2020-12-11 13:54:41 +01:00
parent 0b6fa4ab06
commit be543737a9
16 changed files with 66 additions and 33 deletions

6
package-lock.json generated
View File

@ -4325,9 +4325,9 @@
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
}, },
"ini": { "ini": {
"version": "1.3.5", "version": "1.3.7",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ=="
}, },
"interpret": { "interpret": {
"version": "2.2.0", "version": "2.2.0",

View File

@ -47,7 +47,7 @@
"http-proxy-agent": "4.0.1", "http-proxy-agent": "4.0.1",
"https-proxy-agent": "5.0.0", "https-proxy-agent": "5.0.0",
"image-type": "4.1.0", "image-type": "4.1.0",
"ini": "1.3.5", "ini": "1.3.7",
"is-svg": "4.2.1", "is-svg": "4.2.1",
"jimp": "0.16.1", "jimp": "0.16.1",
"jsdom": "^16.4.0", "jsdom": "^16.4.0",

View File

@ -18,9 +18,9 @@ class AndExp extends Expression {
this.subExpressions = subExpressions; this.subExpressions = subExpressions;
} }
execute(inputNoteSet, searchContext) { execute(inputNoteSet, executionContext) {
for (const subExpression of this.subExpressions) { for (const subExpression of this.subExpressions) {
inputNoteSet = subExpression.execute(inputNoteSet, searchContext); inputNoteSet = subExpression.execute(inputNoteSet, executionContext);
} }
return inputNoteSet; return inputNoteSet;

View File

@ -10,14 +10,14 @@ class ChildOfExp extends Expression {
this.subExpression = subExpression; this.subExpression = subExpression;
} }
execute(inputNoteSet, searchContext) { execute(inputNoteSet, executionContext) {
const subInputNoteSet = new NoteSet(); const subInputNoteSet = new NoteSet();
for (const note of inputNoteSet.notes) { for (const note of inputNoteSet.notes) {
subInputNoteSet.addAll(note.parents); subInputNoteSet.addAll(note.parents);
} }
const subResNoteSet = this.subExpression.execute(subInputNoteSet, searchContext); const subResNoteSet = this.subExpression.execute(subInputNoteSet, executionContext);
const resNoteSet = new NoteSet(); const resNoteSet = new NoteSet();

View File

@ -11,9 +11,9 @@ class DescendantOfExp extends Expression {
this.subExpression = subExpression; this.subExpression = subExpression;
} }
execute(inputNoteSet, searchContext) { execute(inputNoteSet, executionContext) {
const subInputNoteSet = new NoteSet(Object.values(noteCache.notes)); const subInputNoteSet = new NoteSet(Object.values(noteCache.notes));
const subResNoteSet = this.subExpression.execute(subInputNoteSet, searchContext); const subResNoteSet = this.subExpression.execute(subInputNoteSet, executionContext);
const subTreeNoteSet = new NoteSet(); const subTreeNoteSet = new NoteSet();

View File

@ -3,10 +3,10 @@
class Expression { class Expression {
/** /**
* @param {NoteSet} inputNoteSet * @param {NoteSet} inputNoteSet
* @param {object} searchContext * @param {object} executionContext
* @return {NoteSet} * @return {NoteSet}
*/ */
execute(inputNoteSet, searchContext) {} execute(inputNoteSet, executionContext) {}
} }
module.exports = Expression; module.exports = Expression;

View File

@ -9,8 +9,8 @@ class NotExp extends Expression {
this.subExpression = subExpression; this.subExpression = subExpression;
} }
execute(inputNoteSet, searchContext) { execute(inputNoteSet, executionContext) {
const subNoteSet = this.subExpression.execute(inputNoteSet, searchContext); const subNoteSet = this.subExpression.execute(inputNoteSet, executionContext);
return inputNoteSet.minus(subNoteSet); return inputNoteSet.minus(subNoteSet);
} }

View File

@ -11,7 +11,7 @@ class NoteCacheFlatTextExp extends Expression {
this.tokens = tokens; this.tokens = tokens;
} }
execute(inputNoteSet, searchContext) { execute(inputNoteSet, executionContext) {
// has deps on SQL which breaks unit test so needs to be dynamically required // has deps on SQL which breaks unit test so needs to be dynamically required
const noteCacheService = require('../../note_cache/note_cache_service'); const noteCacheService = require('../../note_cache/note_cache_service');
const resultNoteSet = new NoteSet(); const resultNoteSet = new NoteSet();
@ -22,7 +22,7 @@ class NoteCacheFlatTextExp extends Expression {
if (retPath) { if (retPath) {
const noteId = retPath[retPath.length - 1]; const noteId = retPath[retPath.length - 1];
searchContext.noteIdToNotePath[noteId] = retPath; executionContext.noteIdToNotePath[noteId] = retPath;
resultNoteSet.add(noteCache.notes[noteId]); resultNoteSet.add(noteCache.notes[noteId]);
} }

View File

@ -21,11 +21,11 @@ class OrExp extends Expression {
this.subExpressions = subExpressions; this.subExpressions = subExpressions;
} }
execute(inputNoteSet, searchContext) { execute(inputNoteSet, executionContext) {
const resultNoteSet = new NoteSet(); const resultNoteSet = new NoteSet();
for (const subExpression of this.subExpressions) { for (const subExpression of this.subExpressions) {
resultNoteSet.mergeIn(subExpression.execute(inputNoteSet, searchContext)); resultNoteSet.mergeIn(subExpression.execute(inputNoteSet, executionContext));
} }
return resultNoteSet; return resultNoteSet;

View File

@ -20,8 +20,8 @@ class OrderByAndLimitExp extends Expression {
this.subExpression = null; // it's expected to be set after construction this.subExpression = null; // it's expected to be set after construction
} }
execute(inputNoteSet, searchContext) { execute(inputNoteSet, executionContext) {
let {notes} = this.subExpression.execute(inputNoteSet, searchContext); let {notes} = this.subExpression.execute(inputNoteSet, executionContext);
notes.sort((a, b) => { notes.sort((a, b) => {
for (const {valueExtractor, smaller, larger} of this.orderDefinitions) { for (const {valueExtractor, smaller, larger} of this.orderDefinitions) {

View File

@ -10,14 +10,14 @@ class ParentOfExp extends Expression {
this.subExpression = subExpression; this.subExpression = subExpression;
} }
execute(inputNoteSet, searchContext) { execute(inputNoteSet, executionContext) {
const subInputNoteSet = new NoteSet(); const subInputNoteSet = new NoteSet();
for (const note of inputNoteSet.notes) { for (const note of inputNoteSet.notes) {
subInputNoteSet.addAll(note.children); subInputNoteSet.addAll(note.children);
} }
const subResNoteSet = this.subExpression.execute(subInputNoteSet, searchContext); const subResNoteSet = this.subExpression.execute(subInputNoteSet, executionContext);
const resNoteSet = new NoteSet(); const resNoteSet = new NoteSet();

View File

@ -37,7 +37,7 @@ class PropertyComparisonExp extends Expression {
this.comparator = comparator; this.comparator = comparator;
} }
execute(inputNoteSet, searchContext) { execute(inputNoteSet, executionContext) {
const resNoteSet = new NoteSet(); const resNoteSet = new NoteSet();
for (const note of inputNoteSet.notes) { for (const note of inputNoteSet.notes) {

View File

@ -12,7 +12,7 @@ class RelationWhereExp extends Expression {
this.subExpression = subExpression; this.subExpression = subExpression;
} }
execute(inputNoteSet, searchContext) { execute(inputNoteSet, executionContext) {
const candidateNoteSet = new NoteSet(); const candidateNoteSet = new NoteSet();
for (const attr of noteCache.findAttributes('relation', this.relationName)) { for (const attr of noteCache.findAttributes('relation', this.relationName)) {
@ -20,7 +20,7 @@ class RelationWhereExp extends Expression {
if (inputNoteSet.hasNoteId(note.noteId)) { if (inputNoteSet.hasNoteId(note.noteId)) {
const subInputNoteSet = new NoteSet([attr.targetNote]); const subInputNoteSet = new NoteSet([attr.targetNote]);
const subResNoteSet = this.subExpression.execute(subInputNoteSet, searchContext); const subResNoteSet = this.subExpression.execute(subInputNoteSet, executionContext);
if (subResNoteSet.hasNote(attr.targetNote)) { if (subResNoteSet.hasNote(attr.targetNote)) {
if (attr.isInheritable) { if (attr.isInheritable) {

View File

@ -12,7 +12,7 @@ class SubTreeExp extends Expression {
this.subTreeNoteId = subTreeNoteId; this.subTreeNoteId = subTreeNoteId;
} }
execute(inputNoteSet, searchContext) { execute(inputNoteSet, executionContext) {
const subTreeNote = noteCache.notes[this.subTreeNoteId]; const subTreeNote = noteCache.notes[this.subTreeNoteId];
if (!subTreeNote) { if (!subTreeNote) {

View File

@ -15,6 +15,26 @@ class SearchResult {
get noteId() { get noteId() {
return this.notePathArray[this.notePathArray.length - 1]; return this.notePathArray[this.notePathArray.length - 1];
} }
computeScore(tokens) {
this.score = 0;
const chunks = this.notePathTitle.toLowerCase().split(" ");
for (const chunk of chunks) {
for (const token of tokens) {
if (chunk === token) {
this.score += 4 * token.length;
}
else if (chunk.startsWith(token)) {
this.score += 2 * token.length;
}
else if (chunk.includes(token)) {
this.score += token.length;
}
}
}
}
} }
module.exports = SearchResult; module.exports = SearchResult;

View File

@ -13,9 +13,10 @@ const cls = require('../../cls.js');
/** /**
* @param {Expression} expression * @param {Expression} expression
* @param {SearchContext} searchContext
* @return {SearchResult[]} * @return {SearchResult[]}
*/ */
function findNotesWithExpression(expression) { function findNotesWithExpression(expression, searchContext) {
const hoistedNote = noteCache.notes[cls.getHoistedNoteId()]; const hoistedNote = noteCache.notes[cls.getHoistedNoteId()];
let allNotes = (hoistedNote && hoistedNote.noteId !== 'root') let allNotes = (hoistedNote && hoistedNote.noteId !== 'root')
? hoistedNote.subtreeNotes ? hoistedNote.subtreeNotes
@ -27,27 +28,39 @@ function findNotesWithExpression(expression) {
const allNoteSet = new NoteSet(allNotes); const allNoteSet = new NoteSet(allNotes);
const searchContext = { const executionContext = {
noteIdToNotePath: {} noteIdToNotePath: {}
}; };
const noteSet = expression.execute(allNoteSet, searchContext); const noteSet = expression.execute(allNoteSet, executionContext);
const searchResults = noteSet.notes const searchResults = noteSet.notes
.map(note => searchContext.noteIdToNotePath[note.noteId] || noteCacheService.getSomePath(note)) .map(note => executionContext.noteIdToNotePath[note.noteId] || noteCacheService.getSomePath(note))
.filter(notePathArray => notePathArray.includes(cls.getHoistedNoteId())) .filter(notePathArray => notePathArray.includes(cls.getHoistedNoteId()))
.map(notePathArray => new SearchResult(notePathArray)); .map(notePathArray => new SearchResult(notePathArray));
for (const res of searchResults) {
res.computeScore(searchContext.highlightedTokens);
}
if (!noteSet.sorted) { if (!noteSet.sorted) {
// sort results by depth of the note. This is based on the assumption that more important results
// are closer to the note root.
searchResults.sort((a, b) => { searchResults.sort((a, b) => {
if (a.score > b.score) {
return -1;
} else if (a.score < b.score) {
return 1;
}
// if score does not decide then sort results by depth of the note.
// This is based on the assumption that more important results are closer to the note root.
if (a.notePathArray.length === b.notePathArray.length) { if (a.notePathArray.length === b.notePathArray.length) {
return a.notePathTitle < b.notePathTitle ? -1 : 1; return a.notePathTitle < b.notePathTitle ? -1 : 1;
} }
return a.notePathArray.length < b.notePathArray.length ? -1 : 1; return a.notePathArray.length < b.notePathArray.length ? -1 : 1;
}); });
} }
return searchResults; return searchResults;
@ -86,7 +99,7 @@ function findNotesWithQuery(query, searchContext) {
return []; return [];
} }
return findNotesWithExpression(expression); return findNotesWithExpression(expression, searchContext);
}, 20); }, 20);
} }