ਮੈਂ OpenSearch ਅਤੇ CJK ਨਾਲ ਟਾਈਪੋ-ਟੋਲਰੈਂਟ (typo-tolerant) ਸਰਚ ਕਿਵੇਂ ਜੋੜਿਆ
ਜ਼ੀਰੋ-ਰਿਜ਼ਲਟ (zero-result) ਕੁਐਰੀਆਂ ਸਾਡੇ ਵਾਚ ਟਾਈਮ ਨੂੰ ਖਤਮ ਕਰ ਰਹੀਆਂ ਸਨ।
ਇੱਕ ਸਾਲ ਲਈ, TopVideoHub ਨੇ ਸਰਚ ਲਈ SQLite FTS5 ਦੀ ਵਰਤੋਂ ਕੀਤੀ। ਇਹ ਸਹੀ ਮੈਚਾਂ (exact matches) ਲਈ ਕੰਮ ਕਰਦਾ ਸੀ। ਪਰ ਜਦੋਂ ਯੂਜ਼ਰਸ ਟਾਈਪੋ (typos) ਕਰਦੇ ਸਨ, ਤਾਂ ਇਹ ਫੇਲ ਹੋ ਜਾਂਦਾ ਸੀ।
ਲੋਕ "demon slayer" ਦੀ ਬਜਾਏ "demon slyer" ਸਰਚ ਕਰਦੇ ਸਨ। ਉਹਨਾਂ ਨੇ ਜਾਪਾਨੀ ਜਾਂ ਕੋਰੀਅਨ ਟਾਈਟਲ ਵਿੱਚ ਵਾਧੂ ਸਪੇਸ (spaces) ਪਾ ਦਿੱਤੀਆਂ। ਕਿਉਂਕਿ FTS5 ਸਿਰਫ਼ ਸਹੀ ਟੋਕਨਾਂ (tokens) ਨੂੰ ਮੈਚ ਕਰਦਾ ਹੈ, ਇੱਕ ਛੋਟੀ ਜਿਹੀ ਗਲਤੀ ਦਾ ਮਤਲਬ ਸੀ ਜ਼ੀਰੋ ਰਿਜ਼ਲਟ। ਯੂਜ਼ਰਸ ਦੁਬਾਰਾ ਸਰਚ ਨਹੀਂ ਕਰਦੇ ਸਨ। ਉਹ ਸਿਰਫ਼ ਚਲੇ ਜਾਂਦੇ ਸਨ।
ਮੈਂ ਸਾਡੀ ਟਾਈਟਲ ਸਰਚ ਨੂੰ OpenSearch 'ਤੇ ਤਬਦੀਲ ਕਰ ਦਿੱਤਾ। ਇੱਥੇ ਦੱਸਿਆ ਗਿਆ ਹੈ ਕਿ ਮੈਂ ਇੱਕ ਬਹੁ-ਭਾਸ਼ਾਈ (multilingual) ਦਰਸ਼ਕਾਂ ਲਈ ਇਸ ਨੂੰ ਕਿਵੇਂ ਹੱਲ ਕੀਤਾ।
ਸਟੈਂਡਰਡ ਫਜ਼ੀਨੈੱਸ (Standard Fuzziness) ਨਾਲ ਸਮੱਸਿਆ
ਜ਼ਿਆਦਾਤਰ ਟਿਊਟੋਰਿਅਲ ਟਾਈਪੋ ਨੂੰ ਠੀਕ ਕਰਨ ਲਈ "fuzziness" ਦੀ ਵਰਤੋਂ ਕਰਨ ਦੀ ਸਲਾਹ ਦਿੰਦੇ ਹਨ। ਇਹ ਅੰਗਰੇਜ਼ੀ ਲਈ ਤਾਂ ਕੰਮ ਕਰਦਾ ਹੈ, ਪਰ ਚੀਨੀ, ਜਾਪਾਨੀ ਅਤੇ ਕੋਰੀਅਨ (CJK) ਟੈਕਸਟ ਲਈ ਫੇਲ ਹੋ ਜਾਂਦਾ ਹੈ।
- Edit distance CJK ਲਈ ਮਾੜਾ ਹੈ। CJK ਵਿੱਚ ਇੱਕ ਟਾਈਪੋ ਦਾ ਮਤਲਬ ਅਕਸਰ ਪੂਰੀ ਤਰ੍ਹਾਂ ਗਲਤ ਅੱਖਰ ਦੀ ਵਰਤੋਂ ਕਰਨਾ ਹੁੰਦਾ ਹੈ।
- ਸਟੈਂਡਰਡ ਫਜ਼ੀਨੈੱਸ ਅਰਥਹੀਣ (semantic garbage) ਨਤੀਜੇ ਦਿੰਦੀ ਹੈ। ਇਹ "fire" ਨੂੰ "water" ਨਾਲ ਮੈਚ ਕਰ ਸਕਦੀ ਹੈ ਕਿਉਂਕਿ ਉਹ ਇੱਕ ਐਡਿਟ ਦੂਰ ਹਨ।
- ਟੋਕਨਾਈਜ਼ੇਸ਼ਨ (Tokenization) ਮੁਸ਼ਕਲ ਹੈ। CJK ਭਾਸ਼ਾਵਾਂ ਸ਼ਬਦਾਂ ਦੇ ਵਿਚਕਾਰ ਸਪੇਸ ਦੀ ਵਰਤੋਂ ਨਹੀਂ ਕਰਦੀਆਂ।
ਹੱਲ: ਇੱਕ ਮਲਟੀ-ਫੀਲਡ ਅਪ੍ਰੋਚ (Multi-Field Approach)
ਮੈਂ ਸਾਰੇ ਟੈਕਸਟ ਨਾਲ ਇੱਕੋ ਜਿਹਾ ਵਿਵਹਾਰ ਕਰਨਾ ਬੰਦ ਕਰ ਦਿੱਤਾ। ਮੈਂ ਇੱਕ ਲੌਜੀਕਲ ਟਾਈਟਲ ਫੀਲਡ ਬਣਾਈ ਜੋ ਤਿੰਨ ਵੱਖ-ਵੱਖ ਤਰੀਕਿਆਂ ਨਾਲ ਇੰਡੈਕਸ (index) ਕਰਦੀ ਹੈ:
- Latin ਅਤੇ Romaji: ਮੈਂ fuzziness ਨੂੰ ਇਨੇਬਲ (enable) ਕਰਕੇ ਸਟੈਂਡਰਡ ਟੋਕਨਾਈਜ਼ੇਸ਼ਨ ਦੀ ਵਰਤੋਂ ਕੀਤੀ। ਮੈਂ ਪ੍ਰੀਫਿਕਸ ਲੈਂਥ (prefix length) 1 ਸੈੱਟ ਕੀਤੀ। ਇਹ ਯਕੀਨੀ ਬਣਾਉਂਦਾ ਹੈ ਕਿ "demon", "demn" ਨਾਲ ਮੈਚ ਹੋ ਜਾਵੇ ਪਰ "lemon", "demon" ਨਾਲ ਮੈਚ ਨਾ ਹੋਵੇ।
- CJK ਟੈਕਸਟ: ਮੈਂ CJK bigram analyzer ਅਤੇ ਇੱਕ ICU normalizer ਦੀ ਵਰਤੋਂ ਕੀਤੀ। ਮੈਂ fuzziness ਨੂੰ OFF ਕਰ ਦਿੱਤਾ। ਇਸ ਦੀ ਬਜਾਏ, ਮੈਂ 70% ਦਾ ਮਿਨੀਮਮ ਮੈਚ ਥ੍ਰੈਸ਼ਹੋਲਡ (minimum match threshold) ਵਰਤਿਆ।
- Autocomplete: ਮੈਂ search-as-you-type ਨਤੀਜਿਆਂ ਲਈ edge-ngram ਫੀਲਡ ਦੀ ਵਰਤੋਂ ਕੀਤੀ।
ਆਰਕੀਟੈਕਚਰ ਅਤੇ ਡੇਟਾ ਸੁਰੱਖਿਆ (Architecture and Data Safety)
ਮੈਂ SQLite ਨੂੰ ਸਿੰਗਲ ਸੋਰਸ ਆਫ ਟ੍ਰੂਥ (single source of truth) ਵਜੋਂ ਰੱਖਿਆ। OpenSearch ਇੱਕ ਤੇਜ਼, ਰੀਬਿਲਡ ਹੋਣ ਵਾਲੇ ਇੰਡੈਕਸ ਵਜੋਂ ਕੰਮ ਕਰਦਾ ਹੈ।
- ਮੈਂ OpenSearch ਵਿੱਚ ਬਲਕ ਬੈਚਸ (bulk batches) ਵਿੱਚ ਅਪਡੇਟਸ ਭੇਜਣ ਲਈ PHP ਦੀ ਵਰਤੋਂ ਕਰਦਾ ਹਾਂ।
- ਮੈਂ ਯੂਜ਼ਰ ਰਿਕਵੈਸਟ (user request) ਦੌਰਾਨ ਕਦੇ ਵੀ ਇੰਡੈਕਸਿੰਗ ਨਹੀਂ ਚਲਾਉਂਦਾ।
- ਮੈਂ "drift" ਦੀ ਜਾਂਚ ਕਰਨ ਲਈ ਇੱਕ Python ਸਕ੍ਰਿਪਟ ਚਲਾਉਂਦਾ ਹਾਂ। ਇਹ ਯਕੀਨੀ ਬਣਾਉਂਦਾ ਹੈ ਕਿ OpenSearch ਦੀ ਗਿਣਤੀ SQLite ਦੀ ਗਿਣਤੀ ਨਾਲ ਮੇਲ ਖਾਂਦੀ ਹੈ।
ਨਤੀਜੇ
ਬਦਲਾਅ ਬਹੁਤ ਵੱਡਾ ਸੀ:
- ਜ਼ੀਰੋ-ਰਿਜ਼ਲਟ ਕੁਐਰੀਆਂ 14% ਤੋਂ ਘਟ ਕੇ 3% ਤੋਂ ਵੀ ਘੱਟ ਰਹਿ ਗਈਆਂ।
- ਸਰਚ ਸੈਸ਼ਨ ਲੰਬੇ ਹੋ ਗਏ ਕਿਉਂਕਿ ਯੂਜ਼ਰਸ ਨੂੰ ਉਹ ਤੁਰੰਤ ਮਿਲ ਗਿਆ ਜੋ ਉਹ ਚਾਹੁੰਦੇ ਸਨ।
- Latency ਲਗਭਗ 40ms ਦੇ ਆਸ-ਪਾਸ ਘੱਟ ਰਹੀ।
ਜੇਕਰ ਤੁਸੀਂ ਇੱਕ ਬਹੁ-ਭਾਸ਼ਾਈ ਦਰਸ਼ਕਾਂ ਨੂੰ ਸੇਵਾ ਪ੍ਰਦਾਨ ਕਰਦੇ ਹੋ, ਤਾਂ ਯਾਦ ਰੱਖੋ: ਟਾਈਪੋ ਟੋਲਰੈਂਸ ਅਤੇ CJK ਮੈਚਿੰਗ ਦੋ ਵੱਖ-ਵੱਖ ਸਮੱਸਿਆਵਾਂ ਹਨ। ਤੁਹਾਨੂੰ ਦੋ ਵੱਖ-ਵੱਖ ਹੱਲਾਂ ਦੀ ਲੋੜ ਹੈ।
