* Search for partial keyword matches and be case insensitive.

* Show keyword results before regular ones.
* Show full name, type of keyword and title of containing doc.
This commit is contained in:
Georg Brandl 2008-09-24 08:46:33 +00:00
parent b21d71abfd
commit c4b660c5e0
2 changed files with 50 additions and 20 deletions

View File

@ -33,7 +33,8 @@ class _JavaScriptIndex(object):
SUFFIX = ')'
def dumps(self, data):
return self.PREFIX + json.dumps(data) + self.SUFFIX
return self.PREFIX + json.dumps(data, separators=(',', ':')) \
+ self.SUFFIX
def loads(self, s):
data = s[len(self.PREFIX):-len(self.SUFFIX)]
@ -94,6 +95,8 @@ class IndexBuilder(object):
self._titles = {}
# stemmed word -> set(filenames)
self._mapping = {}
# desctypes -> index
self._desctypes = {'module': 0}
def load(self, stream, format):
"""Reconstruct from frozen data."""
@ -104,9 +107,10 @@ class IndexBuilder(object):
if not isinstance(frozen, dict):
raise ValueError('old format')
index2fn = frozen['filenames']
self._titles = dict(zip(frozen['filenames'], frozen['titles']))
self._titles = dict(zip(index2fn, frozen['titles']))
self._mapping = dict((k, set(index2fn[i] for i in v))
for (k, v) in frozen['terms'].iteritems())
# no need to load keywords/desctypes
def dump(self, stream, format):
"""Dump the frozen index to a stream."""
@ -117,14 +121,20 @@ class IndexBuilder(object):
def get_keyword_map(self):
"""Return a dict of all keywords."""
rv = {}
dt = self._desctypes
for kw, (ref, _, _, _) in self.env.modules.iteritems():
rv[kw] = (ref, 'module', 'module-' + kw)
rv[kw] = (ref, 0, 'module-' + kw)
for kw, (ref, ref_type) in self.env.descrefs.iteritems():
rv[kw] = (ref, ref_type, kw)
try:
i = dt[ref_type]
except KeyError:
i = len(dt)
dt[ref_type] = i
rv[kw] = (ref, i, kw)
return rv
def freeze(self):
"""Create a useable data structure for serializing."""
"""Create a usable data structure for serializing."""
filenames = self._titles.keys()
titles = self._titles.values()
fn2index = dict((f, i) for (i, f) in enumerate(filenames))
@ -134,7 +144,8 @@ class IndexBuilder(object):
terms=dict((k, [fn2index[fn] for fn in v])
for (k, v) in self._mapping.iteritems()),
keywords=dict((k, (fn2index[v[0]],) + v[1:]) for k, v in
self.get_keyword_map().iteritems())
self.get_keyword_map().iteritems()),
desctypes=dict((v, k) for (k, v) in self._desctypes.items()),
)
def prune(self, filenames):

View File

@ -294,7 +294,7 @@ var Search = {
var excluded = [];
var hlwords = [];
var tmp = query.split(/\s+/);
var keyword = (tmp.length == 1) ? tmp[0] : null;
var keyword = (tmp.length == 1) ? tmp[0].toLowerCase() : null;
for (var i = 0; i < tmp.length; i++) {
// stem the word
var word = stemmer.stemWord(tmp[i]).toLowerCase();
@ -321,19 +321,31 @@ var Search = {
var filenames = this._index.filenames;
var titles = this._index.titles;
var words = this._index.terms;
var keywords = this._index.keywords;
var desctypes = this._index.desctypes;
var fileMap = {};
var files = null;
var results = [];
var keywordResults = [];
var regularResults = [];
$('#search-progress').empty();
// lookup the keyword
if (keyword != null) {
var match = this._index.keywords[keyword];
if (match)
results.push([filenames[match[0]], titles[match[0]], match[2]]);
for (var kw in keywords) {
if (kw.toLowerCase().indexOf(keyword, kw.lastIndexOf('.')) > -1) {
match = keywords[kw];
descr = desctypes[match[1]] + _(', in ') + titles[match[0]];
keywordResults.push([filenames[match[0]], kw, match[2], descr]);
}
}
}
// sort descending by keyword
keywordResults.sort(function(a, b) {
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
});
// perform the search on the required words
for (var i = 0; i < searchwords.length; i++) {
var word = searchwords[i];
@ -350,8 +362,7 @@ var Search = {
}
}
// now check if the files are in the correct
// areas and if the don't contain excluded words
// now check if the files don't contain excluded words
for (var file in fileMap) {
var valid = true;
@ -371,14 +382,14 @@ var Search = {
// if we have still a valid result we can add it
// to the result list
if (valid)
regularResults.push([filenames[file], titles[file], null]);
regularResults.push([filenames[file], titles[file], null, null]);
}
// delete unused variables in order to not waste
// memory until list is retrieved completely
delete filenames, titles, words;
// now sort the regular results by title
// now sort the regular results descending by title
regularResults.sort(function(a, b) {
var left = a[1].toLowerCase();
var right = b[1].toLowerCase();
@ -386,7 +397,7 @@ var Search = {
});
// combine both
results = regularResults.concat(results);
var results = regularResults.concat(keywordResults);
// print the results
var resultCount = results.length;
@ -400,13 +411,21 @@ var Search = {
item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX +
highlightstring +
(item[2] ? '#' + item[2] : '')).html(item[1]));
$.get('_sources/' + item[0] + '.txt', function(data) {
listItem.append($.makeSearchSummary(data, searchwords, hlwords));
if (item[3]) {
listItem.append($('<span> (' + item[3] + ')</span>'));
Search.output.append(listItem);
listItem.slideDown(10, function() {
listItem.slideDown(5, function() {
displayNextItem();
});
});
} else {
$.get('_sources/' + item[0] + '.txt', function(data) {
listItem.append($.makeSearchSummary(data, searchwords, hlwords));
Search.output.append(listItem);
listItem.slideDown(5, function() {
displayNextItem();
});
});
}
}
// search finished, update title and status message
else {