brief: | ขณะนี้ i18n.site รองรับการค้นหาข้อความแบบเต็มแบบไร้เซิร์ฟเวอร์
บทความนี้แนะนำการใช้งานเทคโนโลยีการค้นหาข้อความแบบเต็มส่วนหน้า รวมถึงดัชนีกลับด้านที่สร้างโดย IndexedDB การค้นหาคำนำหน้า การเพิ่มประสิทธิภาพการแบ่งส่วนคำ และการสนับสนุนหลายภาษา
เมื่อเปรียบเทียบกับโซลูชันที่มีอยู่แล้ว การค้นหาข้อความแบบเต็มส่วนหน้าของ i18n.site มีขนาดเล็กและรวดเร็ว เหมาะสำหรับเว็บไซต์ขนาดเล็กและขนาดกลาง เช่น เอกสารและบล็อก และพร้อมใช้งานแบบออฟไลน์
หลังจากหลายสัปดาห์ของการพัฒนา i18n.site (เครื่องมือสร้างเว็บไซต์ markdown multilingualtranslation & แบบคงที่ล้วนๆ) รองรับการค้นหาข้อความแบบเต็มส่วนหน้าอย่างแท้จริง
บทความนี้จะแบ่งปันการใช้งานทางเทคนิคของการค้นหาข้อความแบบเต็มส่วนหน้า i18n.site
เพื่อ i18n.site ประสบการณ์การค้นหา
รหัสโอเพ่นซอร์ส : ค้นหาเคอร์เนล / อินเทอร์เฟซแบบโต้ตอบ
สำหรับเว็บไซต์ขนาดเล็กและขนาดกลางแบบคงที่ล้วนๆ เช่น เอกสาร/บล็อกส่วนตัว การสร้างแบ็กเอนด์การค้นหาข้อความแบบเต็มที่สร้างขึ้นเองนั้นหนักเกินไป และการค้นหาข้อความแบบเต็มแบบไร้บริการเป็นตัวเลือกที่พบบ่อยกว่า
โซลูชันการค้นหาข้อความแบบเต็มแบบไร้เซิร์ฟเวอร์แบ่งออกเป็นสองประเภทกว้างๆ:
ประการ algolia.com ผู้ให้บริการการค้นหาบุคคลที่สามที่คล้ายกันจะจัดเตรียมส่วนประกอบส่วนหน้าสำหรับการค้นหาข้อความแบบเต็ม
บริการดังกล่าวจำเป็นต้องชำระเงินตามปริมาณการค้นหา และมักไม่มีให้บริการสำหรับผู้ใช้ในจีนแผ่นดินใหญ่เนื่องจากปัญหาต่างๆ เช่น การปฏิบัติตามข้อกำหนดของเว็บไซต์
ไม่สามารถใช้แบบออฟไลน์ ไม่สามารถใช้บนอินทราเน็ต และมีข้อจำกัดอย่างมาก บทความนี้ไม่ได้กล่าวถึงมากนัก
ประการที่สองคือการค้นหาข้อความแบบเต็มส่วนหน้าล้วนๆ
ในปัจจุบัน การค้นหาข้อความแบบเต็มส่วนหน้าทั่วไปประกอบด้วย lunrjs และ ElasticLunr.js (ขึ้นอยู่กับการพัฒนารอง lunrjs
)
lunrjs
มีสองวิธีในการสร้างดัชนี และทั้งสองวิธีก็มีปัญหาของตัวเอง
ไฟล์ดัชนีที่สร้างไว้ล่วงหน้า
เนื่องจากดัชนีประกอบด้วยคำจากเอกสารทั้งหมด จึงมีขนาดใหญ่ เมื่อใดก็ตามที่มีการเพิ่มหรือแก้ไขเอกสาร จะต้องโหลดไฟล์ดัชนีใหม่ จะทำให้ผู้ใช้ใช้เวลารอนานขึ้นและใช้แบนด์วิธเป็นจำนวนมาก
โหลดเอกสารและสร้างดัชนีได้ทันที
การสร้างดัชนีเป็นงานที่ต้องใช้การคำนวณสูง การสร้างดัชนีใหม่ทุกครั้งที่คุณเข้าถึงจะทำให้เกิดความล่าช้าอย่างเห็นได้ชัดและประสบการณ์การใช้งานที่ไม่ดี
นอกจาก lunrjs
แล้ว ยังมีโซลูชันการค้นหาข้อความแบบเต็มอื่นๆ เช่น :
fusejs คำนวณความคล้ายคลึงกันระหว่างสตริงที่จะค้นหา
ประสิทธิภาพของโซลูชันนี้แย่มาก และไม่สามารถใช้สำหรับการค้นหาข้อความแบบเต็มได้ (ดู Fuse.js การสืบค้นแบบยาวใช้เวลานานกว่า 10 วินาที จะปรับให้เหมาะสมได้อย่างไร )
TinySearch ให้ใช้ตัวกรอง Bloom เพื่อค้นหา ไม่สามารถใช้สำหรับการค้นหาคำนำหน้าได้ (เช่น ป้อน goo
ค้นหา good
, google
) และไม่สามารถใช้เอฟเฟกต์การเติมคำอัตโนมัติที่คล้ายกันได้
เนื่องจากข้อบกพร่องของโซลูชันที่มีอยู่ i18n.site
จึงพัฒนาโซลูชันการค้นหาข้อความแบบเต็มส่วนหน้าแบบใหม่ซึ่งมีลักษณะดังต่อไปนี้ :
gzip
คือ 6.9KB
(สำหรับการเปรียบเทียบ ขนาดของ lunrjs
คือ 25KB
)indexedb
ซึ่งใช้หน่วยความจำน้อยลงและรวดเร็วด้านล่างนี้ จะมีการแนะนำรายละเอียดการใช้งานด้านเทคนิค i18n.site
การแบ่งส่วนคำใช้การแบ่งส่วนคำดั้งเดิมของเบราว์เซอร์ Intl.Segmenter
และเบราว์เซอร์หลักทั้งหมดรองรับอินเทอร์เฟซนี้
รหัสการแบ่งส่วนคำ coffeescript
มีดังนี้
SEG = new Intl.Segmenter 0, granularity: "word"
seg = (txt) =>
r = []
for {segment} from SEG.segment(txt)
for i from segment.split('.')
i = i.trim()
if i and !'| `'.includes(i) and !/\p{P}/u.test(i)
r.push i
r
export default seg
export segqy = (q) =>
seg q.toLocaleLowerCase()
ใน:
/\p{P}/
คือนิพจน์ทั่วไปที่ตรงกับเครื่องหมายวรรคตอนโดยเฉพาะ ได้แก่: ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _
{ | } ~. -
split('.')
เป็นเพราะการแบ่งส่วนคำของเบราว์เซอร์ Firefox
ไม่ได้แบ่งส่วน .
5 ตารางการจัดเก็บวัตถุถูกสร้างขึ้นใน IndexedDB
:
word
: id -doc
: id - เอกสาร url - หมายเลขเวอร์ชันเอกสารdocWord
: อาร์เรย์ของเอกสาร id - คำ idprefix
: อาร์เรย์ของคำนำหน้า - คำ idrindex
: Word id - เอกสาร id : อาร์เรย์ของหมายเลขบรรทัดส่งผ่านอาร์เรย์ของเอกสาร url
และหมายเลขเวอร์ชัน ver
และค้นหาว่ามีเอกสารอยู่ในตารางที่ doc
หรือไม่ หากไม่มี ให้สร้างดัชนีแบบกลับด้าน ในเวลาเดียวกัน ให้ลบดัชนีกลับด้านสำหรับเอกสารที่ไม่ได้ส่งเข้ามา
ด้วยวิธีนี้ จึงสามารถบรรลุการจัดทำดัชนีแบบเพิ่มหน่วยได้ และลดปริมาณการคำนวณลง
ในการโต้ตอบส่วนหน้า แถบความคืบหน้าในการโหลดของดัชนีสามารถแสดงได้เพื่อหลีกเลี่ยงความล่าช้าเมื่อโหลดเป็นครั้งแรก ดู "แถบความคืบหน้าพร้อมภาพเคลื่อนไหว อิงจาก Single progress + Pure css Implementation" English / Chinese
โครงการนี้ได้ idb บนพื้นฐานของการห่อหุ้มแบบอะซิงโครนัสของ IndexedDB
IndexedDB การอ่านและเขียนเป็นแบบอะซิงโครนัส เมื่อสร้างดัชนี เอกสารจะถูกโหลดพร้อมกันเพื่อสร้างดัชนี
เพื่อหลีกเลี่ยงการสูญเสียข้อมูลบางส่วนที่เกิดจากการเขียนเชิงแข่งขัน คุณสามารถอ้างอิงโค้ด coffeescript
ด้านล่างและเพิ่มแคช ing
ระหว่างการอ่านและการเขียนเพื่อสกัดกั้นการเขียนที่แข่งขันกัน
pusher = =>
ing = new Map()
(table, id, val)=>
id_set = ing.get(id)
if id_set
id_set.add val
return
id_set = new Set([val])
ing.set id, id_set
pre = await table.get(id)
li = pre?.li or []
loop
to_add = [...id_set]
li.push(...to_add)
await table.put({id,li})
for i from to_add
id_set.delete i
if not id_set.size
ing.delete id
break
return
rindexPush = pusher()
prefixPush = pusher()
การค้นหาจะแบ่งกลุ่มคำหลักที่ผู้ใช้ป้อนก่อน
สมมติว่ามี N
คำหลังการแบ่งส่วนคำ เมื่อส่งคืนผลลัพธ์ ผลลัพธ์ที่มีคำหลักทั้งหมดจะถูกส่งคืนก่อน จากนั้นผลลัพธ์ที่มีคำหลัก N-1
, N-2
,..., 1
คำจะถูกส่งกลับ
ผลการค้นหาที่แสดงก่อนจะรับประกันความถูกต้องของการสืบค้น และผลลัพธ์ที่โหลดตามมา (คลิกปุ่มโหลดเพิ่มเติม) จะรับประกันอัตราการเรียกคืน
เพื่อปรับปรุงความเร็วในการตอบสนอง การค้นหาจะใช้ตัวสร้าง yield
เพื่อใช้การโหลดตามความต้องการ และส่งคืน limit
ครั้งที่มีการสอบถามผลลัพธ์
โปรดทราบว่าแต่ละครั้งที่คุณค้นหาอีกครั้งหลังจาก yield
คุณจะต้องเปิดธุรกรรมการสืบค้น IndexedDB
เพื่อแสดงผลการค้นหาในขณะที่ผู้ใช้พิมพ์ เช่น เมื่อป้อน wor
คำที่นำหน้าด้วย wor
เช่น words
และ work
จะแสดงขึ้นมา
เคอร์เนลการค้นหาจะใช้ตาราง prefix
สำหรับคำสุดท้ายหลังจากการแบ่งส่วนคำ เพื่อค้นหาคำทั้งหมดที่นำหน้าด้วย และค้นหาตามลำดับ
ฟังก์ชันป้องกันการสั่นไหว debounce
ยังใช้ในการโต้ตอบส่วนหน้า (ใช้งานดังนี้) เพื่อลดความถี่ของการป้อนข้อมูลของผู้ใช้ที่ทริกเกอร์การค้นหา และลดจำนวนการคำนวณ
export default (wait, func) => {
var timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(func.bind(this, ...args), wait);
};
}
ตารางดัชนีไม่ได้จัดเก็บข้อความต้นฉบับ มีเพียงคำเท่านั้น ซึ่งช่วยลดปริมาณการจัดเก็บ
การเน้นผลการค้นหาจำเป็นต้องโหลดข้อความต้นฉบับซ้ำ และการจับคู่ service worker
สามารถหลีกเลี่ยงการร้องขอเครือข่ายซ้ำได้
ในเวลาเดียวกัน เนื่องจาก service worker
แคชบทความทั้งหมด เมื่อผู้ใช้ทำการค้นหา เว็บไซต์ทั้งหมด รวมถึงการค้นหา จึงสามารถใช้งานแบบออฟไลน์ได้
โซลูชันการค้นหาส่วนหน้าของ i18n.site
ได้รับการปรับให้เหมาะสมสำหรับเอกสาร MarkDown
ฉบับ
เมื่อแสดงผลการค้นหา ชื่อบทจะปรากฏขึ้น และบทจะถูกนำทางเมื่อคลิก
การค้นหาข้อความแบบเต็มแบบกลับด้านนำไปใช้เฉพาะที่ส่วนหน้า โดยไม่ต้องใช้เซิร์ฟเวอร์ เหมาะมากสำหรับเว็บไซต์ขนาดเล็กและขนาดกลาง เช่น เอกสาร และบล็อกส่วนตัว
i18n.site
การค้นหาส่วนหน้าแบบโอเพ่นซอร์สที่พัฒนาตนเองล้วนๆ ขนาดเล็กและการตอบสนองที่รวดเร็ว แก้ไขข้อบกพร่องของการค้นหาข้อความแบบเต็มส่วนหน้าล้วนๆ ในปัจจุบัน และมอบประสบการณ์ผู้ใช้ที่ดีขึ้น