儘管我最近開始用VNote作讀書或讀在線文檔的筆記,但更多的時候,我把經驗型知識都記錄在一個名爲my_note
的Git倉庫中。這個倉庫中有許多.org
文件:javascript
TeX.org
,記錄與LaTeX
相關的問題和解決方法;asm.org
,記錄的是與編寫彙編語言程序相關的問題和解決辦法;cl.org
,記錄的是與編寫Common Lisp代碼相關的問題和解決辦法;這些內容被我稱爲FAQ。儘管不一樣的文件記載着不一樣方面的內容,但它們的格式是一致的:java
A picture is worth a thousand wordsgit
這些問題都比較常見(否則怎麼叫FAQ呢——也許上圖的不算常見吧),回過頭來查找的機率很高。顯然,在紛繁複雜的文字中憑肉眼尋找關鍵字是低效的,即便是祭出grep
,用正則表達式這樣的大殺器來查找也不是特別稱手——由於並不知道怎樣的正則表達式能夠匹配到尋找的內容——也許多寫了關鍵詞,也許少寫了,也許順序不對。github
對於搜索這類非結構的文字資料來講,全文檢索是一個更好的選擇,所以,我是把這些內容丟進ElasticSearch裏再查找的。正則表達式
FAQ中的每個條目,都對應ElasticSearch中的一個文檔,它們都存儲在索引faq
中。一個文檔有以下的字段:json
answer
,即問題的答案;path
,文件絕對路徑,表示文檔來自於哪個文件中的條目;question
,即問題的描述;questionLineNum
,即問題存在於文件的第幾行。解析這些文件的邏輯也很簡單:每當讀入行首爲星號的一行後(這一行即爲問題),便繼續讀入後續的每一行直到再次遇到行首爲星號的行爲止,這些後續讀入的行組成了這個問題的答案。有了問題和答案,即可以導入到ElasticSearch中。最終的腳本以下async
const request = require('co-request'); const fs = require('fs'); function parseFaqOrg(path) { const content = fs.readFileSync(path).toString('utf-8'); const lines = content.split('\n'); const qas = []; let answer = []; let lineNum = 0; let mode; let question; let questionLineNum; for (const line of lines) { lineNum += 1; if (line.startsWith('*')) { if (mode === 'answer') { // 在遇到星號的時候模式已經處於answer中,說明在此以前還有未處理的QA qas.push({ answer: answer.join('\n'), path, question, questionLineNum }); answer = []; question = null; } mode = 'question'; } else { mode = 'answer'; } if (mode === 'answer') { answer.push(line); } else { question = line; questionLineNum = lineNum; } } if (question) { qas.push({ answer: answer.join('\n'), question }); } // console.log(JSON.stringify(qas, null, 2)); return qas; } async function dropFaq() { await request({ method: 'delete', url: 'http://localhost:9200/faq' }); } /** * 重建faq索引並寫入全量的筆記數據 */ async function main() { console.log(new Date().toLocaleString()); await dropFaq(); const dir = '/Users/liutos/Documents/Projects/my_note/faq/'; const basenames = fs.readdirSync(dir); for (const basename of basenames) { const path = dir + basename; const type = basename.match(/(.*)\.org/)[1]; const qas = parseFaqOrg(path); for (const qa of qas) { await request({ body: qa, json: true, method: 'post', url: 'http://localhost:9200/faq/_doc' }); } console.log(`文件${path}處理完畢`); } console.log(new Date().toLocaleString()); } main();
若是想知道我是如何在Emacs中查詢這些FAQ的,能夠參見《在Emacs中搭建筆記查閱系統的嘗試》這篇文章。post
閱讀原文ui