क्या PostgreSQL "उच्चारण असंवेदनशील" टकरावों का समर्थन करता है?


98

Microsoft SQL सर्वर में, एक "उच्चारण असंवेदनशील" कोलाजेशन (डेटाबेस, टेबल या कॉलम के लिए) निर्दिष्ट करना संभव है, जिसका अर्थ है कि यह क्वेरी के लिए संभव है

SELECT * FROM users WHERE name LIKE 'João'

एक Joaoनाम के साथ एक पंक्ति खोजने के लिए ।

मुझे पता है कि PostgreSQL में स्ट्रिंग से unaccent_string कॉन्ट्रिब फ़ंक्शन का उपयोग करके स्ट्रेंट्स से स्ट्रिप करना संभव है , लेकिन मैं सोच रहा हूं कि क्या PostgreSQL इन "एक्सेंट असंवेदनशील" टकरावों का समर्थन करता है इसलिए SELECTउपरोक्त काम करेगा।


अस्वीकार्य के साथ FTS शब्दकोश बनाने के लिए यह उत्तर देखें: stackoverflow.com/a/50595181/124486
इवान कैरोल

क्या आप केस-सेंसिटिविटी या केस असंवेदनशील खोजें चाहते हैं?
इवान कैरोल

जवाबों:


206

उस के लिए अस्वीकार्य मॉड्यूल का उपयोग करें - जो आप से लिंक कर रहे हैं उससे पूरी तरह से अलग है।

unaccent एक टेक्स्ट सर्च डिक्शनरी है, जो लेक्समेस से एक्सेंट (डियाक्रिटिक संकेतों) को हटाती है।

प्रति डेटाबेस एक बार स्थापित करें:

CREATE EXTENSION unaccent;

यदि आपको कोई त्रुटि मिलती है जैसे:

ERROR: could not open extension control file
"/usr/share/postgresql/<version>/extension/unaccent.control": No such file or directory

इस संबंधित उत्तर में दिए गए निर्देश की तरह अपने डेटाबेस सर्वर पर कंट्रिब पैकेज स्थापित करें:

अन्य बातों के अलावा, यह वह फ़ंक्शन प्रदान करता है जिसे unaccent()आप अपने उदाहरण के साथ उपयोग कर सकते हैं (जहां LIKEइसकी आवश्यकता नहीं है)।

SELECT *
FROM   users
WHERE  unaccent(name) = unaccent('João');

सूची

उस तरह के क्वेरी के लिए एक इंडेक्स का उपयोग करने के लिए, अभिव्यक्ति पर एक इंडेक्स बनाएं । हालाँकि , Postgres केवल IMMUTABLEअनुक्रमणिका के कार्यों को स्वीकार करता है। यदि कोई फ़ंक्शन समान इनपुट के लिए एक अलग परिणाम दे सकता है, तो सूचकांक चुपचाप टूट सकता है।

unaccent()केवल STABLEनहींIMMUTABLE

दुर्भाग्य से, unaccent()केवल है STABLE, नहीं IMMUTABLEPgsql- कीड़े पर इस धागे के अनुसार , यह तीन कारणों से है:

  1. यह एक शब्दकोश के व्यवहार पर निर्भर करता है।
  2. इस शब्दकोश का कोई हार्ड-वायर्ड कनेक्शन नहीं है।
  3. इसलिए यह वर्तमान पर भी निर्भर करता है search_path, जो आसानी से बदल सकता है।

वेब पर कुछ ट्यूटोरियल सिर्फ फंक्शन की अस्थिरता को बदलने का निर्देश देते हैं IMMUTABLE। यह ब्रूट-फोर्स विधि कुछ शर्तों के तहत टूट सकती है।

दूसरों को एक सरल IMMUTABLEआवरण समारोह का सुझाव दिया (जैसे मैंने अतीत में खुद किया था)।

इस बात पर बहस जारी है कि क्या दो मापदंडों के साथ वैरिएंट बनाया जाए IMMUTABLEजो स्पष्ट रूप से इस्तेमाल किए गए शब्दकोश की घोषणा करता है। यहाँ या यहाँ पढ़ें ।

एक और विकल्प यह मॉड्यूल होगा जो म्यूथब्रेनज़ unaccent()द्वारा IMMUTABLE फ़ंक्शन के साथ है, गितुब पर प्रदान किया गया है। खुद इसका परीक्षण नहीं किया। मुझे लगता है कि मैं एक बेहतर विचार के साथ आया हूं :

अभी के लिए सबसे अच्छा

यह दृष्टिकोण अन्य समाधानों के रूप में अधिक कुशल है, जो चारों ओर तैर रहा है, और सुरक्षित है । हार्ड-वायर्ड स्कीमा-योग्य फ़ंक्शन और डिक्शनरी के साथ दो-पैरामीटर फ़ॉर्म को निष्पादित करते हुए
एक IMMUTABLESQL आवरण फ़ंक्शन बनाएं ।

चूंकि एक गैर-अपरिवर्तनीय फ़ंक्शन नेस्टिंग किया है, इसलिए फ़ंक्शन इनलाइनिंग को अक्षम कर देगा, इसे C-फ़ंक्शन की एक प्रति के आधार पर, (नकली) भी घोषित IMMUTABLEकिया जाएगा। इसका एकमात्र उद्देश्य SQL फ़ंक्शन रैपर में उपयोग किया जाना है। इसका उपयोग अपने आप करने के लिए नहीं है।

परिष्कार की आवश्यकता है क्योंकि सी फ़ंक्शन की घोषणा में शब्दकोश को हार्ड-वायर करने का कोई तरीका नहीं है। (C कोड को स्वयं हैक करने की आवश्यकता होगी।) SQL आवरण फ़ंक्शन ऐसा करता है और फ़ंक्शन इनलाइनिंग और अभिव्यक्ति अनुक्रमित दोनों की अनुमति देता है ।

CREATE OR REPLACE FUNCTION public.immutable_unaccent(regdictionary, text)
  RETURNS text LANGUAGE c IMMUTABLE PARALLEL SAFE STRICT AS
'$libdir/unaccent', 'unaccent_dict';

CREATE OR REPLACE FUNCTION public.f_unaccent(text)
  RETURNS text LANGUAGE sql IMMUTABLE PARALLEL SAFE STRICT AS
$func$
SELECT public.immutable_unaccent(regdictionary 'public.unaccent', $1)
$func$;

PARALLEL SAFE9.5 या उससे अधिक उम्र के दोनों कार्यों के लिए ड्रॉप ।

publicस्कीमा होना जहां आपने एक्सटेंशन स्थापित किया है ( publicडिफ़ॉल्ट है)।

स्पष्ट प्रकार की घोषणा ( regdictionary) दुर्भावनापूर्ण उपयोगकर्ताओं द्वारा फ़ंक्शन के अतिभारित वेरिएंट के साथ काल्पनिक हमलों के खिलाफ बचाव करती है।

पहले, मैंने अस्वीकार्य मॉड्यूल के साथ भेजे गए STABLEफ़ंक्शन के आधार पर एक आवरण समारोह की वकालत की unaccent()। उस अक्षम फ़ंक्शन को इनलाइनिंग । यह संस्करण उस सरल आवरण समारोह की तुलना में दस गुना अधिक तेज़ी से निष्पादित होता है जो मैंने पहले यहां किया था।
और यह पहले से ही पहले संस्करण के रूप में दोगुना तेज़ था जो SET search_path = public, pg_tempफ़ंक्शन में जोड़ा गया - जब तक मुझे पता नहीं चला कि शब्दकोश स्कीमा-योग्य हो सकता है, भी। अभी भी (पोस्टग्रेज 12) प्रलेखन से बहुत स्पष्ट नहीं है।

यदि आपको C फ़ंक्शन बनाने के लिए आवश्यक विशेषाधिकारों की कमी है, तो आप दूसरे सर्वोत्तम कार्यान्वयन पर वापस आते हैं : मॉड्यूल द्वारा प्रदान किए गए फ़ंक्शन के IMMUTABLEआसपास एक फ़ंक्शन आवरण STABLE unaccent():

CREATE OR REPLACE FUNCTION public.f_unaccent(text)
  RETURNS text AS
$func$
SELECT public.unaccent('public.unaccent', $1)  -- schema-qualify function and dictionary
$func$  LANGUAGE sql IMMUTABLE PARALLEL SAFE STRICT;

अंत में, प्रश्नों को तेज़ बनाने के लिए अभिव्यक्ति सूचकांक :

CREATE INDEX users_unaccent_name_idx ON users(public.f_unaccent(name));

फ़ंक्शन या शब्दकोश में किसी भी परिवर्तन के बाद इस फ़ंक्शन को शामिल करने वाले अनुक्रमणिकाओं को फिर से बनाना याद रखें , जैसे कि एक इन-प्लेस प्रमुख रिलीज़ अपग्रेड जो अनुक्रमणिका को फिर से नहीं बनाएगा। हाल की प्रमुख रिलीज में सभी unaccentमॉड्यूल के लिए अपडेट थे ।

अनुक्रमणिका से मिलान करने के लिए क्वेरीज़ को समायोजित करें (ताकि क्वेरी योजनाकार इसका उपयोग करेगा):

SELECT * FROM users
WHERE  f_unaccent(name) = f_unaccent('João');

आपको सही अभिव्यक्ति में फ़ंक्शन की आवश्यकता नहीं है। वहां आप 'Joao'सीधे तरह से बिना तार के भी आपूर्ति कर सकते हैं।

तीव्र फ़ंक्शन अभिव्यक्ति इंडेक्स का उपयोग करके बहुत तेज़ प्रश्नों का अनुवाद नहीं करता है । यह पूर्व-संकलित मूल्यों पर काम करता है और पहले से ही बहुत तेज है। लेकिन अनुक्रमणिका लाभ का उपयोग नहीं करते हुए अनुरक्षण रखरखाव और क्वेरीज़।

क्लाइंट प्रोग्राम के लिए सुरक्षा पोस्टग्रेज 10.3 / 9.6.8 आदि के साथ कड़ी कर दी गई है। आपको किसी भी इंडेक्स में उपयोग किए जाने के दौरान स्कीमा-क्वालिफाइड फ़ंक्शन और डिक्शनरी नाम की आवश्यकता होती है। देख:

ligatures

Postgres में 9.5 या उससे अधिक 'ँ' या संयुक्ताक्षर 'ß' है मैन्युअल रूप से विस्तार किया जा करने के लिए (आपको लगता है कि जरूरत है), के बाद से unaccent()हमेशा एक विकल्प एक पत्र:

SELECT unaccent('Œ Æ œ æ ß');

unaccent
----------
E A e a S

आप इस अपडेट को पोस्टग्रेस 9.6 में अस्वीकार्य पसंद करेंगे :

बढ़ाएँ contrib/unaccentके मानक unaccent.rulesयूनिकोड के लिए जाना जाता सब डायाक्रिटिक्स को संभालने के लिए फ़ाइल, और सही ढंग से संयुक्ताक्षर का विस्तार (थॉमस मुनरो, लियोनार्ड बेनेडेट्टी)

बोल्ड जोर मेरा। अब हमें मिलता है:

SELECT unaccent('Œ Æ œ æ ß');

unaccent
----------
OE AE oe ae ss

पैटर्न मिलान

के लिए LIKEया ILIKEमनमाने ढंग से पैटर्न के साथ, pg_trgmPostgreSQL 9.1 या बाद में मॉड्यूल के साथ गठबंधन करें । एक ट्रिम GIN (आमतौर पर बेहतर) या GIST अभिव्यक्ति सूचकांक बनाएं। GIN के लिए उदाहरण:

CREATE INDEX users_unaccent_name_trgm_idx ON users
USING gin (f_unaccent(name) gin_trgm_ops);

जैसे प्रश्नों के लिए इस्तेमाल किया जा सकता है:

SELECT * FROM users
WHERE  f_unaccent(name) LIKE ('%' || f_unaccent('João') || '%');

सादे बीटी से बनाए रखने के लिए GIN और GIST इंडेक्स अधिक महंगे हैं:

बस बाएं-एंकर पैटर्न के लिए सरल समाधान हैं। पैटर्न मिलान और प्रदर्शन के बारे में अधिक जानकारी:

pg_trgm"समानता" ( %) और "दूरी" ( <->) के लिए उपयोगी ऑपरेटर भी प्रदान करता है ।

ट्राइग्राम इंडेक्स, ~एट अल के साथ सरल नियमित अभिव्यक्तियों का भी समर्थन करता है । और मामले असंवेदनशील पैटर्न के साथ मिलान ILIKE:


आपके समाधान में, अनुक्रमित का उपयोग किया जाता है, या मुझे एक सूचकांक बनाने की आवश्यकता होगी unaccent(name)?
डैनियल सेरोडियो

@ErwinBrandstetter Psql 9.1.4 में, मैं "फ़ंक्शन को इंडेक्स एक्सप्रेशन में IMMUTABLE के रूप में चिह्नित किया जाना चाहिए", क्योंकि अस्वीकार्य फ़ंक्शन STM के बजाय INMUTABLE है। आप क्या सलाह देते हैं?
e3matheus

1
@ e3matheus: मेरे द्वारा दिए गए पिछले समाधान का परीक्षण न करने के लिए दोषी महसूस करना, मैंने जांच की और इस समस्या के लिए एक नए और बेहतर (IMHO) समाधान के साथ अपने जवाब को अपडेट किया जो अब तक तैर रहा है।
एरविन ब्रैंडस्टैटर

क्या utf8_general_ciइस तरह के मुद्दों का जवाब नहीं है ?
मेड

5
आपके उत्तर उतने ही अच्छे हैं जितने कि डाक्यूमेंट्स डाक्यूमेंट: अभूतपूर्व!
इलेक्ट्रोटाइप

6

नहीं, PostgreSQL उस अर्थ में टकरावों का समर्थन नहीं करता है

PostgreSQL उस तरह के टकराव का समर्थन नहीं करता है (उच्चारण असंवेदनशील है या नहीं) क्योंकि कोई भी तुलना बराबर नहीं लौट सकती जब तक कि चीजें बाइनरी-बराबर नहीं होती हैं। ऐसा इसलिए है क्योंकि आंतरिक रूप से यह हैश इंडेक्स जैसी चीजों के लिए बहुत सारी जटिलताएं पेश करता है। इस कारण से उनके सख्त अर्थों में टकराव केवल आदेश को प्रभावित करते हैं न कि समानता को।

समाधान

फुल-टेक्स्ट-डिक्शनरी डिक्शनरी जो अनैकेंट्स लेक्समेस है।

FTS के लिए, आप अपने खुद के डिक्शनरी को परिभाषित कर सकते हैं unaccent,

CREATE EXTENSION unaccent;

CREATE TEXT SEARCH CONFIGURATION mydict ( COPY = simple );
ALTER TEXT SEARCH CONFIGURATION mydict
  ALTER MAPPING FOR hword, hword_part, word
  WITH unaccent, simple;

तब आप एक कार्यात्मक सूचकांक के साथ सूचकांक कर सकते हैं,

-- Just some sample data...
CREATE TABLE myTable ( myCol )
  AS VALUES ('fóó bar baz'),('qux quz');

-- No index required, but feel free to create one
CREATE INDEX ON myTable
  USING GIST (to_tsvector('mydict', myCol));

अब आप इसे बहुत सरलता से क्वेरी कर सकते हैं

SELECT *
FROM myTable
WHERE to_tsvector('mydict', myCol) @@ 'foo & bar'

    mycol    
-------------
 fóó bar baz
(1 row)

यह सभी देखें

खुद से बेखबर।

unaccentमॉड्यूल भी बाहर है कि जांच करने के लिए, बिना FTS-एकीकरण से ही इस्तेमाल किया जा सकता इरविन के जवाब


2

मुझे पूरा यकीन है कि PostgreSQL collation के लिए अंतर्निहित ऑपरेटिंग सिस्टम पर निर्भर करता है। यह नए कोलाज बनाने और कोलाज को कस्टमाइज़ करने का समर्थन करता है । मुझे यकीन नहीं है कि आपके लिए कितना काम हो सकता है, हालांकि। (काफी हो सकता है।)


1
नई टक्कर समर्थन वर्तमान में ऑपरेटिंग सिस्टम स्थानों के लिए रैपर और उपनाम तक सीमित है। यह बहुत बुनियादी है। फ़िल्टर फ़ंक्शंस, कस्टम तुलनित्र, या सच्चे कस्टम कोलाज़ेशन के लिए आपको किसी भी चीज़ का कोई समर्थन नहीं है।
क्रेग रिंगर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.