Version 0.8.0: gefaltete Indizes markiert, Review abgeschlossen
index -x schreibt Offset-x in den Kopf der .i-Datei, search bisektiert in der Ordnung des Index. Beim Umstieg .h- und mit -x gebaute .i-Indizes neu bauen.
This commit is contained in:
+27
-8
@@ -14,6 +14,9 @@ module Rdb
|
||||
ENTRY_WIDTH = 9
|
||||
SUFFIX = { 'h' => '.h', 'i' => '.i', 'r' => '.r' }.freeze
|
||||
FIXED_HEAD = "Offset\n------\n"
|
||||
# Second head column of an inverted index built with index -x: its keys are
|
||||
# sorted without regard to case, for search -x (like look).
|
||||
FOLDED = 'Offset-x'
|
||||
|
||||
Row = Struct.new(:from, :to, :line) do
|
||||
def cells
|
||||
@@ -119,7 +122,8 @@ module Rdb
|
||||
k = data.column(keycol)
|
||||
ents = rows.map { |r| [r.cells[k].to_s, r.from] }
|
||||
ents = ents.sort_by { |key, off| [fold ? key.strip.downcase : key.strip, off] }
|
||||
Rdb.write_file(path + '.i', "#{keycol}\tOffset\n#{'-' * keycol.size}\t------\n" + ents.map { |key, off| "#{key}\t#{off}\n" }.join)
|
||||
off_col = fold ? FOLDED : 'Offset'
|
||||
Rdb.write_file(path + '.i', Table.head_text([keycol, off_col]) + ents.map { |key, off| "#{key}\t#{off}\n" }.join)
|
||||
when 'h'
|
||||
k = data.column(keycol)
|
||||
slots = [rows.size * 2, 2].max
|
||||
@@ -151,6 +155,10 @@ module Rdb
|
||||
io.read(ENTRY_WIDTH).to_i
|
||||
end
|
||||
|
||||
def folded?(ipath)
|
||||
File.open(ipath, 'rb') { |f| f.gets.to_s.chomp("\n").split("\t")[1] == FOLDED }
|
||||
end
|
||||
|
||||
# Entries of an inverted index (.i) from the first key that is not below
|
||||
# target, found by bisecting on byte positions. Yields hashes like
|
||||
# read_inverted does.
|
||||
@@ -225,10 +233,13 @@ module Rdb
|
||||
when 'b'
|
||||
rows = live_rows(data)
|
||||
k = idxs[0]
|
||||
lo = rows.bsearch_index { |r| (partial ? norm(r.cells[k], true)[0, keyvals[0].strip.size] : r.cells[k].strip) >= (partial ? norm(keyvals[0], true) : keyvals[0].strip) }
|
||||
# The table is sorted by the key as it is (case counts), so a partial,
|
||||
# case-blind search cannot bisect; it reads the rows in order.
|
||||
lo = partial ? 0 : rows.bsearch_index { |r| r.cells[k].strip >= keyvals[0].strip }
|
||||
if lo
|
||||
rows[lo..].each do |r|
|
||||
break unless matches?(r.cells[k], keyvals[0], partial, exact)
|
||||
break if !partial && r.cells[k].strip != keyvals[0].strip
|
||||
next unless matches?(r.cells[k], keyvals[0], partial, exact)
|
||||
|
||||
hits << Hit.new(r, 0, 8)
|
||||
break if first
|
||||
@@ -242,10 +253,17 @@ module Rdb
|
||||
r = data.row_at(off) and hits << Hit.new(r, FIXED_HEAD.bytesize + ENTRY_WIDTH * (n - 1), FIXED_HEAD.bytesize + ENTRY_WIDTH * n)
|
||||
end
|
||||
when 'i'
|
||||
target = partial ? norm(keyvals[0], true) : keyvals[0].strip
|
||||
below = ->(key) { (partial ? norm(key, true)[0, keyvals[0].strip.size] : key.strip) < target }
|
||||
each_inverted_from(path + '.i', below) do |e|
|
||||
break unless matches?(e[:key], keyvals[0], partial, exact)
|
||||
# The index is in folded order (index -x) or not. Bisect in that order,
|
||||
# then keep the entries that match. A partial (case-blind) search in an
|
||||
# unfolded index has no order to use and reads the whole index.
|
||||
ip = path + '.i'
|
||||
fold = folded?(ip)
|
||||
target = norm(keyvals[0], fold || partial)
|
||||
cut = ->(key) { norm(key, fold || partial).then { |k| partial ? k[0, target.size] : k } }
|
||||
below = fold || !partial ? ->(key) { cut.(key) < target } : ->(_key) { false }
|
||||
each_inverted_from(ip, below) do |e|
|
||||
break if (fold || !partial) && cut.(e[:key]) != target
|
||||
next unless matches?(e[:key], keyvals[0], partial, exact)
|
||||
|
||||
r = data.row_at(e[:offset])
|
||||
hits << Hit.new(r, e[:from], e[:to]) if r
|
||||
@@ -318,7 +336,8 @@ module Rdb
|
||||
name = File.binread(ip).lines.first.split("\t")[0]
|
||||
key = cells[data_head.index(name)].to_s
|
||||
ents = read_inverted(ip)
|
||||
pos = ents.find { |e| e[:key].strip > key.strip }
|
||||
fold = folded?(ip)
|
||||
pos = ents.find { |e| norm(e[:key], fold) > norm(key, fold) }
|
||||
line = "#{key}\t#{row_from}\n"
|
||||
if pos then splice(ip, pos[:from], pos[:from], line)
|
||||
else Rdb.write_file(ip, File.binread(ip) + line)
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Rdb
|
||||
VERSION = '0.7.0'
|
||||
VERSION = '0.8.0'
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user