2ea39a3d41
Kiwix ranks by keyword overlap, which the package doc has said since it was written: "why is the sky blue" finds a TV episode. queryKiwix sent the whole Russian sentence, because the verbatim path added by V-508 skips the rewriter that would have reduced it. Measured against the Russian ZIM on 2026-08-09, over eight questions. Four reach the right article where they did not: TCP was "Перехват TCP-соединения" and is TCP, фотосинтез was "C4-фотосинтез" and is Фотосинтез, Линус Торвальдс was "Tux", and "кто написал Войну и мир" was "Радуйся, мир (Доктор Кто)". Two were already right and stay right. Two are still wrong and were wrong before. Nothing regressed. kiwix.Topic drops the narrative request, the interrogative and a verb behind one, and keeps everything else. A word it cannot classify is more likely the topic than noise. TitlePath tries the exact article first, since a ZIM is addressable by title and a wrong title is a 404. The gate this task set out to build does not exist. Query-to-passage cosine scored 0.79-0.91 on answerable questions and 0.75-0.84 on unanswerable ones, and the sets overlap. The wrong TCP article scored 0.8653, above five of six unanswerable rows. e5 measures topic, not whether the passage answers. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013ptwopxyo3Z2kwFckHkLvN
52 lines
2.2 KiB
Go
52 lines
2.2 KiB
Go
package kiwix
|
|
|
|
import "testing"
|
|
|
|
// The cases the 2026-08-09 measurement turned on, plus the ones a topic must
|
|
// not damage. Each left column returned a wrong article when it was sent whole.
|
|
func TestTopicKeepsTheThingTheQuestionIsAbout(t *testing.T) {
|
|
cases := []struct{ utterance, want string }{
|
|
{"что такое TCP?", "TCP"},
|
|
{"что такое фотосинтез", "фотосинтез"},
|
|
{"кто такой Линус Торвальдс?", "Линус Торвальдс"},
|
|
{"кто написал Войну и мир", "Войну и мир"},
|
|
{"расскажи про битву при Ватерлоо", "битву при Ватерлоо"},
|
|
{"what is photosynthesis", "photosynthesis"},
|
|
// No question word, so there is nothing to drop. The topic is the
|
|
// whole utterance and the search is what it was before.
|
|
{"столица Франции", "столица Франции"},
|
|
{"почему небо голубое", "небо голубое"},
|
|
}
|
|
for _, c := range cases {
|
|
if got := Topic(c.utterance); got != c.want {
|
|
t.Errorf("Topic(%q) = %q, want %q", c.utterance, got, c.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// A verb only goes when a question word already went. Otherwise "написал
|
|
// отчёт" loses the verb that names what he means.
|
|
func TestTopicDropsAVerbOnlyBehindAQuestionWord(t *testing.T) {
|
|
if got := Topic("написал отчёт"); got != "написал отчёт" {
|
|
t.Errorf("Topic dropped a leading verb with no question word: %q", got)
|
|
}
|
|
}
|
|
|
|
// Question words alone reduce to nothing, and the caller reads that as "no
|
|
// topic" and searches the sentence rather than searching the empty string.
|
|
func TestTopicIsEmptyWhenNothingIsLeft(t *testing.T) {
|
|
for _, q := range []string{"что такое?", "кто?", "почему", "???"} {
|
|
if got := Topic(q); got != "" {
|
|
t.Errorf("Topic(%q) = %q, want empty", q, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTitlePathEscapesAndUnderscores(t *testing.T) {
|
|
got := TitlePath("wikipedia_ru_all_maxi_2026-02", "Чёрная дыра")
|
|
want := "/content/wikipedia_ru_all_maxi_2026-02/A/%D0%A7%D1%91%D1%80%D0%BD%D0%B0%D1%8F_%D0%B4%D1%8B%D1%80%D0%B0"
|
|
if got != want {
|
|
t.Errorf("TitlePath = %q, want %q", got, want)
|
|
}
|
|
}
|