summaryrefslogtreecommitdiff
path: root/sphinx/themes/basic
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2013-01-04 11:17:32 +0100
committerGeorg Brandl <georg@python.org>2013-01-04 11:17:32 +0100
commit49766d3c533dcd55c6496215cb7de45741172d9a (patch)
tree94c092d7c610706705a8c5cde409860cd6c45b76 /sphinx/themes/basic
parent1bd15df78fadbbca09d9c8a4d4c8f8bbe451c9d0 (diff)
downloadsphinx-49766d3c533dcd55c6496215cb7de45741172d9a.tar.gz
Closes #1067: implement pluggable search scorer and tweak scoring to give good results. Patch by Hernan Grecco.
Diffstat (limited to 'sphinx/themes/basic')
-rw-r--r--sphinx/themes/basic/static/searchtools.js_t144
1 files changed, 101 insertions, 43 deletions
diff --git a/sphinx/themes/basic/static/searchtools.js_t b/sphinx/themes/basic/static/searchtools.js_t
index e22b76db..e91e9c66 100644
--- a/sphinx/themes/basic/static/searchtools.js_t
+++ b/sphinx/themes/basic/static/searchtools.js_t
@@ -9,34 +9,41 @@
*
*/
+{{ search_language_stemming_code|safe }}
+
+{% if search_scorer_tool %}
+{{ search_scorer_tool|safe }}
+{% else %}
/**
- * helper function to return a node containing the
- * search summary for a given text. keywords is a list
- * of stemmed words, hlwords is the list of normal, unstemmed
- * words. the first one is used to find the occurance, the
- * latter for highlighting it.
+ * Simple result scoring code.
*/
-
-jQuery.makeSearchSummary = function(text, keywords, hlwords) {
- var textLower = text.toLowerCase();
- var start = 0;
- $.each(keywords, function() {
- var i = textLower.indexOf(this.toLowerCase());
- if (i > -1)
- start = i;
- });
- start = Math.max(start - 120, 0);
- var excerpt = ((start > 0) ? '...' : '') +
- $.trim(text.substr(start, 240)) +
- ((start + 240 - text.length) ? '...' : '');
- var rv = $('<div class="context"></div>').text(excerpt);
- $.each(hlwords, function() {
- rv = rv.highlightText(this, 'highlighted');
- });
- return rv;
+var Scorer = {
+ // Implement the following function to further tweak the score for each result
+ // The function takes a result array [filename, title, anchor, descr, score]
+ // and returns the new score.
+ /*
+ score: function(result) {
+ return result[4];
+ },
+ */
+
+ // query matches the full name of an object
+ objNameMatch: 11,
+ // or matches in the last dotted part of the object name
+ objPartialMatch: 6,
+ // Additive scores depending on the priority of the object
+ objPrio: {0: 15, // used to be importantResults
+ 1: 5, // used to be objectResults
+ 2: -5}, // used to be unimportantResults
+ // Used when the priority is not in the mapping.
+ objPrioDefault: 0,
+
+ // query found in title
+ title: 15,
+ // query found in terms
+ term: 5
};
-
-{{ search_language_stemming_code|safe }}
+{% endif %}
/**
* Search Module
@@ -184,23 +191,40 @@ var Search = {
}
// lookup as search terms in fulltext
- results = results.concat(this.performTermsSearch(searchterms, excluded, terms, 0))
- .concat(this.performTermsSearch(searchterms, excluded, titleterms, 20));
+ results = results.concat(this.performTermsSearch(searchterms, excluded, terms, Scorer.term))
+ .concat(this.performTermsSearch(searchterms, excluded, titleterms, Scorer.title));
// delete unused variables in order to not waste memory until list is
// retrieved completely
delete filenames, titles, terms, titleterms;
- // now sort the regular results by score (in opposite order of appearance,
- // since the display function below uses pop() to retrieve items)
+ // let the scorer override scores with a custom scoring function
+ if (Scorer.score) {
+ for (i = 0; i < results.length; i++)
+ results[i][4] = Scorer.score(results[i]);
+ }
+
+ // now sort the results by score (in opposite order of appearance, since the
+ // display function below uses pop() to retrieve items) and then
+ // alphabetically
results.sort(function(a, b) {
var left = a[4];
var right = b[4];
- return (left > right) ? 1 : ((left < right) ? -1 : 0);
+ if (left > right) {
+ return 1;
+ } else if (left < right) {
+ return -1;
+ } else {
+ // same score: sort alphabetically
+ left = a[1].toLowerCase();
+ right = b[1].toLowerCase();
+ return (left > right) ? -1 : ((left < right) ? 1 : 0);
+ }
});
- console.info('search results:', results);
- Search.lastresults = results.slice(); // a copy
+ // for debugging
+ //Search.lastresults = results.slice(); // a copy
+ //console.info('search results:', Search.lastresults);
// print the results
var resultCount = results.length;
@@ -236,7 +260,7 @@ var Search = {
$.get(DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' +
item[0] + '.txt', function(data) {
if (data != '') {
- listItem.append($.makeSearchSummary(data, searchterms, hlterms));
+ listItem.append(Search.makeSearchSummary(data, searchterms, hlterms));
Search.output.append(listItem);
}
listItem.slideDown(5, function() {
@@ -281,6 +305,16 @@ var Search = {
for (var name in objects[prefix]) {
var fullname = (prefix ? prefix + '.' : '') + name;
if (fullname.toLowerCase().indexOf(object) > -1) {
+ var score = 0;
+ var parts = fullname.split('.');
+ // check for different match types: exact matches of full name or
+ // "last name" (i.e. last dotted part)
+ if (fullname == object || parts[parts.length - 1] == object) {
+ score += Scorer.objNameMatch;
+ // matches in last name
+ } else if (parts[parts.length - 1].indexOf(object) > -1) {
+ score += Scorer.objPartialMatch;
+ }
var match = objects[prefix][name];
var objname = objnames[match[1]][2];
var title = titles[match[0]];
@@ -301,20 +335,17 @@ var Search = {
}
}
var descr = objname + _(', in ') + title;
+
anchor = match[3];
if (anchor == '')
anchor = fullname;
else if (anchor == '-')
anchor = objnames[match[1]][1] + '-' + fullname;
- result = [filenames[match[0]], fullname, '#'+anchor, descr, 0];
- var score;
- switch (match[2]) {
- case 1: // normal results -- display between important and fulltext
- score = 5; break;
- case 0: // "important" results -- show directly after title results
- score = 10; break;
- case 2: // "unimportant" results -- show after fulltext results
- score = -10; break;
+ // add custom score for some objects according to scorer
+ if (Scorer.objPrio.hasOwnProperty(match[2])) {
+ score += Scorer.objPrio[match[2]];
+ } else {
+ score += Scorer.objPrioDefault;
}
results.push([filenames[match[0]], fullname, '#'+anchor, descr, score]);
}
@@ -372,11 +403,38 @@ var Search = {
}
// if we have still a valid result we can add it to the result list
- if (valid)
+ if (valid) {
results.push([filenames[file], titles[file], '', null, score]);
+ }
}
return results;
},
+
+ /**
+ * helper function to return a node containing the
+ * search summary for a given text. keywords is a list
+ * of stemmed words, hlwords is the list of normal, unstemmed
+ * words. the first one is used to find the occurance, the
+ * latter for highlighting it.
+ */
+ makeSearchSummary : function(text, keywords, hlwords) {
+ var textLower = text.toLowerCase();
+ var start = 0;
+ $.each(keywords, function() {
+ var i = textLower.indexOf(this.toLowerCase());
+ if (i > -1)
+ start = i;
+ });
+ start = Math.max(start - 120, 0);
+ var excerpt = ((start > 0) ? '...' : '') +
+ $.trim(text.substr(start, 240)) +
+ ((start + 240 - text.length) ? '...' : '');
+ var rv = $('<div class="context"></div>').text(excerpt);
+ $.each(hlwords, function() {
+ rv = rv.highlightText(this, 'highlighted');
+ });
+ return rv;
+ }
};
$(document).ready(function() {