Permalink
Browse files

Implement range queries.

  • Loading branch information...
1 parent f4c731a commit b5ae4a65cfa313a6f6e5b95793bf83dbc35fe4c6 Albin Stjerna committed Feb 23, 2013
Showing with 45 additions and 9 deletions.
  1. +29 −8 db/xapian_music.py
  2. +16 −1 test/test.py
View
37 db/xapian_music.py
@@ -5,23 +5,22 @@
from db.dirtree import get_songs
import json
import os
+import time
# a mapping of query term/aliases → xapian prefixes.
# most of these are also keys to the song[] dict.
# Prefixes from http://xapian.org/docs/omega/termprefixes.html
PREFIXES = {'artist' : 'A',
'title' : 'S',
- 'year' : 'Y',
'path' : 'U',
'album' : 'XALBUM',
- 'mtime' : 'XMTIME',
- 'title' : 'XTITLE',
- 'tracknumber' : 'XTRACKNR'}
+ 'title' : 'XTITLE'}
-NUMERIC_PREFIXES = {}
-
-# Use slot #1 for tags
-#XAPIAN_TAGS = 1
+# These numeric prefixes will also be used as data slots.
+NUMERIC_PREFIXES = {'year' : 'Y',
+ 'mtime' : 'XMTIME',
+ 'tracknumber' : 'XTRACKNR',
+ 'rating' : 'XRATING'}
def index(datapath, dbpath):
# Create or open the database we're going to be writing to.
@@ -31,6 +30,18 @@ def index(datapath, dbpath):
termgenerator = xapian.TermGenerator()
termgenerator.set_stemmer(xapian.Stem("en"))
+ def make_value(s, term):
+ "Parse various string values and return suitable numeric representations."
+ if term == 'year':
+ # This is in a date string format due to serialization.
+ return xapian.sortable_serialise(int(s))
+ if term == 'mtime':
+ return xapian.sortable_serialise(time.mktime(time.strptime(s)))
+ if term == 'rating':
+ return xapian.sortable_serialise(max([float(n) for n in s]))
+ else:
+ return xapian.sortable_serialise(int(s))
+
for song in get_songs(datapath):
# We make a document and tell the term generator to use this.
doc = xapian.Document()
@@ -46,6 +57,11 @@ def index(datapath, dbpath):
#if pos < len(term):
termgenerator.increase_termpos()
+ for data_slot, term in enumerate(NUMERIC_PREFIXES):
+ if song[term]:
+ doc.add_value(data_slot, make_value(song[term], term))
+
+
# Store all the fields for display purposes.
doc.set_data(unicode(json.dumps(song)))
@@ -77,6 +93,11 @@ def parse_query(q):
for term in PREFIXES:
queryparser.add_prefix(term, PREFIXES[term])
+ for data_slot, term in enumerate(NUMERIC_PREFIXES):
+ queryparser.add_valuerangeprocessor(
+ xapian.NumberValueRangeProcessor(data_slot, term, True)
+ )
+
# And parse the query
return queryparser.parse_query(q)
View
17 test/test.py
@@ -291,7 +291,22 @@ def test_search_genre():
assert False
def test_search_year_interval():
- assert False
+
+ def search_interval_year(db):
+ q_all = 'year..3000'
+ q_2010 = 'year..2010'
+ q_1999 = 'year..1999'
+ q_early_00s = 'year1999..2004'
+ songs_all = search(db, q_all)
+ songs_2010 = search(db, q_2010)
+ songs_1999 = search(db, q_1999)
+ songs_early_00s = search(db, q_early_00s)
+ assert len(songs_all) == 6
+ assert len(songs_2010) == 5
+ assert len(songs_1999) == 0
+ assert len(songs_early_00s) == 2
+
+ with_index(search_interval_year)
def test_search_rating_interval():
assert False

0 comments on commit b5ae4a6

Please sign in to comment.