def index_message_threading doc, entry, old_entry
    return if old_entry && (entry[:refs] == old_entry[:refs]) && (entry[:replytos] == old_entry[:replytos])
    children = term_docids(mkterm(:ref, entry[:message_id])).map { |docid| @xapian.document docid }
    parent_ids = entry[:refs] + entry[:replytos]
    parents = parent_ids.map { |id| find_doc id }.compact
    thread_members = SavingHash.new { [] }
    (children + parents).each do |doc2|
      thread_ids = doc2.value(THREAD_VALUENO).split ','
      thread_ids.each { |thread_id| thread_members[thread_id] << doc2 }
    end
    thread_ids = thread_members.empty? ? [entry[:message_id]] : thread_members.keys
    thread_ids.each { |thread_id| doc.add_term mkterm(:thread, thread_id) }
    parent_ids.each { |ref| doc.add_term mkterm(:ref, ref) }
    doc.add_value THREAD_VALUENO, (thread_ids * ',')
  end
def index_message_threading doc, entry, old_entry
    return if old_entry && (entry[:refs] == old_entry[:refs]) && (entry[:replytos] == old_entry[:replytos])
    children = term_docids(mkterm(:ref, entry[:message_id])).map { |docid| @xapian.document docid }
    parent_ids = entry[:refs] + entry[:replytos]
    parents = parent_ids.map { |id| find_doc id }.compact
    thread_members = SavingHash.new { [] }
    (children + parents).each do |doc2|
      thread_ids = doc2.value(THREAD_VALUENO).split ','
      thread_ids.each { |thread_id| thread_members[thread_id] << doc2 }
    end
    thread_ids = thread_members.empty? ? [entry[:message_id]] : thread_members.keys
    thread_ids.each { |thread_id| doc.add_term mkterm(:thread, thread_id) }
    parent_ids.each { |ref| doc.add_term mkterm(:ref, ref) }
    doc.add_value THREAD_VALUENO, (thread_ids * ',')
  end
Assign a set of thread ids to the document. This is a hybrid of the runtime
 search done by the Ferret index and the index-time union done by previous
 versions of the Xapian index. We first find the thread ids of all messages
 with a reference to or from us. If that set is empty, we use our own
 message id. Otherwise, we use all the thread ids we previously found. In
 the common case there's only one member in that set, but if we're the
 missing link between multiple previously unrelated threads we can have
 more. XapianIndex#each_message_in_thread_for follows the thread ids when
 searching so the user sees a single unified thread.