OpenSearch-ഉം CJK-ഉം ഉപയോഗിച്ച് ടൈപ്പോ-ടോളറന്റ് (Typo-Tolerant) സെർച്ച് ഞാൻ എങ്ങനെ ചേർത്തു
സെർച്ച് റിസൾട്ടുകൾ ഒന്നും ലഭിക്കാത്ത അവസ്ഥ (Zero-result queries) ഞങ്ങളുടെ വാച്ച് ടൈം (watch time) കുറയ്ക്കുന്നുണ്ടായിരുന്നു.
ഒരു വർഷത്തോളം, TopVideoHub സെർച്ചിനായി SQLite FTS5 ആണ് ഉപയോഗിച്ചിരുന്നത്. കൃത്യമായ വാക്കുകൾ തിരയുമ്പോൾ ഇത് നന്നായി പ്രവർത്തിച്ചു. എന്നാൽ ഉപയോക്താക്കൾ അക്ഷരത്തെറ്റുകൾ (typos) വരുത്തുമ്പോൾ ഇത് പരാജയപ്പെട്ടു.
ആളുകൾ "demon slayer" എന്നതിന് പകരം "demon slyer" എന്ന് തിരഞ്ഞു. ജാപ്പനീസ് അല്ലെങ്കിൽ കൊറിയൻ തലക്കെട്ടുകളിൽ അവർ അനാവശ്യമായ സ്പേസുകൾ ചേർത്തു. FTS5 കൃത്യമായ ടോക്കണുകൾ (tokens) മാത്രമേ പൊരുത്തപ്പെടുത്തുകയുള്ളൂ എന്നതുകൊണ്ട്, ഒരു ചെറിയ അക്ഷരത്തെറ്റ് പോലും റിസൾട്ടുകൾ ഒന്നും ലഭിക്കാത്ത അവസ്ഥയ്ക്ക് കാരണമായി. ഉപയോക്താക്കൾ വീണ്ടും തിരയാൻ ശ്രമിക്കാതെ വെറുതെ സൈറ്റ് വിട്ടുപോയി.
ഞാൻ ഞങ്ങളുടെ ടൈറ്റിൽ സെർച്ച് OpenSearch-ലേക്ക് മാറ്റി. ഒരു ബഹുഭാഷാ പ്രേക്ഷകർക്കായി (multilingual audience) ഞാൻ ഇത് എങ്ങനെ പരിഹരിച്ചു എന്ന് താഴെ വിവരിക്കുന്നു.
സ്റ്റാൻഡേർഡ് ഫസിനസ്സിൻ്റെ (Standard Fuzziness) പ്രശ്നങ്ങൾ
അക്ഷരത്തെറ്റുകൾ പരിഹരിക്കാൻ "fuzziness" ഉപയോഗിക്കാൻ മിക്ക ട്യൂട്ടോറിയലുകളും നിർദ്ദേശിക്കാറുണ്ട്. ഇത് ഇംഗ്ലീഷിന് അനുയോജ്യമാണ്, എന്നാൽ ചൈനീസ്, ജാപ്പനീസ്, കൊറിയൻ (CJK) ടെക്സ്റ്റുകൾക്ക് ഇത് ഫലപ്രദമല്ല.
- CJK-ക്ക് എഡിറ്റ് ഡിസ്റ്റൻസ് (Edit distance) അനുയോജ്യമല്ല. CJK-യിൽ ഒരു അക്ഷരത്തെറ്റ് എന്നാൽ പലപ്പോഴും തെറ്റായ ഒരു അക്ഷരം തന്നെ ഉപയോഗിക്കുക എന്നാണ് അർത്ഥം.
- സ്റ്റാൻഡേർഡ് ഫസിനസ്സ് അർത്ഥശൂന്യമായ ഫലങ്ങൾ (semantic garbage) നൽകിയേക്കാം. ഉദാഹരണത്തിന്, "fire", "water" എന്നിവ തമ്മിൽ ഒരു എഡിറ്റ് വ്യത്യാസം മാത്രം ഉള്ളതുകൊണ്ട് അവ തമ്മിൽ പൊരുത്തപ്പെട്ടേക്കാം.
- ടോക്കണൈസേഷൻ (Tokenization) പ്രയാസകരമാണ്. CJK ഭാഷകളിൽ വാക്കുകൾക്കിടയിൽ സ്പേസുകൾ ഉപയോഗിക്കാറില്ല.
പരിഹാരം: ഒരു മൾട്ടി-ഫീൽഡ് സമീപനം (Multi-Field Approach)
എല്ലാ ടെക്സ്റ്റുകളെയും ഒരേപോലെ കാണുന്നത് ഞാൻ നിർത്തി. മൂന്ന് വ്യത്യസ്ത രീതികളിൽ ഇൻഡക്സ് ചെയ്യുന്ന ഒരു ലോജിക്കൽ ടൈറ്റിൽ ഫീൽഡ് ഞാൻ നിർമ്മിച്ചു:
- Latin and Romaji: ഫസിനസ്സ് (fuzziness) എനേബിൾ ചെയ്തുകൊണ്ട് സ്റ്റാൻഡേർഡ് ടോക്കണൈസേഷൻ ഞാൻ ഉപയോഗിച്ചു. ഇതിനായി പ്രിഫിക്സ് ലെങ്ത് (prefix length) 1 ആയി നിശ്ചയിച്ചു. ഇത് "demon" എന്നത് "demn" എന്നതിനോട് പൊരുത്തപ്പെടാൻ സഹായിക്കുന്നു, എന്നാൽ "lemon" എന്നത് "demon" എന്നതിനോട് പൊരുത്തപ്പെടില്ലെന്ന് ഇത് ഉറപ്പാക്കുന്നു.
- CJK Text: ഒരു CJK bigram analyzer-ഉം ICU normalizer-ഉം ഞാൻ ഉപയോഗിച്ചു. ഫസിനസ്സ് ഞാൻ ഓഫ് ചെയ്തു. പകരം, 70% മിനിമം മാച്ച് ത്രെഷോൾഡ് (minimum match threshold) ആണ് ഞാൻ ഉപയോഗിച്ചത്.
- Autocomplete: ടൈപ്പ് ചെയ്യുമ്പോൾ തന്നെ റിസൾട്ടുകൾ കാണിക്കുന്നതിനായി (search-as-you-type) ഒരു edge-ngram ഫീൽഡ് ഞാൻ ഉപയോഗിച്ചു.
ആർക്കിടെക്ചറും ഡാറ്റാ സുരക്ഷയും (Architecture and Data Safety)
SQLite-നെ ഞാൻ ഏക സ്രോതസ്സായി (single source of truth) നിലനിർത്തി. OpenSearch ഒരു വേഗതയേറിയ, പുനർനിർമ്മിക്കാവുന്ന ഇൻഡക്സ് ആയി പ്രവർത്തിക്കുന്നു.
- ബൾക്ക് ബാച്ചുകളായി (bulk batches) അപ്ഡേറ്റുകൾ OpenSearch-ലേക്ക് എത്തിക്കാൻ ഞാൻ PHP ഉപയോഗിക്കുന്നു.
- ഉപയോക്താക്കളുടെ റിക്വസ്റ്റ് സമയത്ത് ഇൻഡക്സിംഗ് ഒരിക്കലും പ്രവർത്തിപ്പിക്കാറില്ല.
- "ഡ്രിഫ്റ്റ്" (drift) പരിശോധിക്കാൻ ഞാൻ ഒരു Python സ്ക്രിപ്റ്റ് ഉപയോഗിക്കുന്നു. ഇത് OpenSearch-ലെ എണ്ണവും SQLite-ലെ എണ്ണവും തുല്യമാണെന്ന് ഉറപ്പാക്കുന്നു.
ഫലങ്ങൾ
മാറ്റം വളരെ വലുതായിരുന്നു:
- സെർച്ച് റിസൾട്ടുകൾ ഒന്നും ലഭിക്കാത്ത അവസ്ഥ 14%-ൽ നിന്ന് 3%-ൽ താഴെയായി കുറഞ്ഞു.
- ഉപയോക്താക്കൾക്ക് അവർ ആഗ്രഹിച്ച കാര്യങ്ങൾ ഉടൻ തന്നെ ലഭിച്ചതുകൊണ്ട് സെർച്ച് സെഷനുകളുടെ ദൈർഘ്യം വർദ്ധിച്ചു.
- ലേറ്റൻസി (Latency) ഏകദേശം 40ms എന്ന നിലയിൽ കുറവായി തുടരുന്നു.
നിങ്ങൾ ഒരു ബഹുഭാഷാ പ്രേക്ഷകർക്കായി സേവനം നൽകുന്നുണ്ടെങ്കിൽ ഇത് ഓർക്കുക: ടൈപ്പോ ടോളറൻസും (typo tolerance) CJK മാച്ചിംഗും രണ്ട് വ്യത്യസ്ത പ്രശ്നങ്ങളാണ്. അവയ്ക്ക് രണ്ട് വ്യത്യസ്ത പരിഹാരങ്ങൾ ആവശ്യമാണ്.
