sql >> Database teknologi >  >> RDS >> Mysql

Hvordan optimerer man MySQL Boolean Full-Text Search? (Eller hvad skal den erstattes med?) - C#

For det første bør du indse, at RDBMS-understøttelse af fuldtekstindeksering er et hack til at tvinge en teknologi designet til at give effektiv adgang til strukturerede data til at håndtere ustruktureret tekst. (Ja, det er bare mit mening. Hvis det er nødvendigt, kan jeg forsvare det, da jeg forstår begge teknologier særdeles godt.;)

Så hvad kan der gøres for at forbedre søgeydelsen?

Mulighed 1 - "Det bedste værktøj til opgaven"

Den bedste måde at håndtere fuldtekstsøgning inden for et korpus af dokumenter er den brugsteknologi, der er specielt designet til at gøre det, såsom SOLR (Lucene) fra Apache eller Sphinx fra fejl, Sphinx.

Af årsager, der vil blive tydelige nedenfor, anbefaler jeg stærkt denne tilgang.

Mulighed to - Forudindlæs dine resultater

Når man konstruerer tekstbaserede søgeløsninger, er den sædvanlige tilgang at indeksere alle dokumenter til et enkelt søgbart indeks, og selvom dette kan være den mest hensigtsmæssige, er det ikke den eneste fremgangsmåde.

Forudsat at det, du søger efter, let kan kvantificeres til et sæt kendte regler, kunne du tilbyde mere en "guidet" søgningsstil end blot ukvalificeret fuldtekst. Hvad jeg mener med dette er, at hvis din applikation kan have gavn af at guilde brugere til resultater, kan du forudindlæse forskellige sæt resultater baseret på et kendt sæt regler i deres egne tabeller og dermed reducere hovedparten af ​​data, der skal søges i.

Hvis du forventer, at et flertal af dine brugere vil drage fordel af et kendt sæt søgetermer i en kendt rækkefølge, kan du konstruere din søgebrugergrænseflade til at favorisere disse termer.

Så hvis vi antager, at et flertal af brugere leder efter en række forskellige biler, kan du tilbyde foruddefinerede søgninger baseret på model, årgang, stand osv. Din søge-UI ville være udformet som en række rullemenuer for at "guide" brugere til specifikke resultater.

Eller hvis størstedelen af ​​søgningerne vil være for et specifikt hovedemne (f.eks. "biler"), kan du foruddefinere en tabel med kun de poster, du tidligere har identificeret som værende relateret til biler.

Begge disse tilgange ville reducere antallet af poster, der skal søges i, og dermed øge svartider.

Valgmulighed tre - "Rul din egen"

Hvis du ikke kan integrere en ekstern søgeteknologi i dit projekt, og forudindlæsning ikke er en mulighed, er der stadig måder, hvorpå du kan forbedre søgeforespørgselssvarstiderne markant, men de er forskellige baseret på, hvad du skal opnå, og hvordan du forventer, at søgninger udføres .

Hvis du forventer, at brugerne søger ved hjælp af enkelte søgeord eller sætninger og booleske forhold mellem dem, kan du overveje at konstruere din egen 'omvendt indeks ' af dit korpus. (Dette er, hvad MySQL's Boolean Full-Text Search allerede gør, men at gøre det selv giver større kontrol over både hastigheden og nøjagtigheden af ​​søgningen.)

Sådan bygger du et omvendt indeks ud fra dine eksisterende data:

Trin 1. Opret tre tabeller

    // dict - a dictionary containing one row per unique word in corpus  
    create table dict (    
      id int primary key,  
      word varchar  
    )

    // invert - an inverted_index to map words to records in corpus  
    create table invert (    
      id int primary key,  
      rec_id int,  
      word_id int  
    )

    // stopwords - to contain words to ignore when indexing (like a, an, the, etc)
    create table stopwords ( 
      id int primary key,  
      word varchar  
    )

Bemærk:Dette er kun en skitse. Du vil tilføje indekser og begrænsninger osv., når du rent faktisk opretter disse tabeller.

Stopordstabellen bruges til at reducere størrelsen af ​​dit indeks til kun de ord, der har betydning for brugernes forventede forespørgsler. For eksempel er det sjældent nyttigt at indeksere engelske artikler, såsom 'a', 'an', 'the', da de ikke bidrager med nyttig betydning til søgeordssøgninger.

Typisk vil du kræve en stopordsliste specifikt udformet til din ansøgnings behov. Hvis du aldrig forventer, at brugerne medtager udtrykkene "rød", "hvid" eller "blå" i deres forespørgsler, eller hvis disse termer forekommer i hver søgbar post, vil du gerne tilføje dem til din stopordsliste.

Se noten i slutningen af ​​denne besked for instruktioner om brug af din egen stopordsliste i MySQL.

Se også:

Trin 2. Byg det omvendte indeks

For at opbygge et inverteret indeks fra dine eksisterende poster skal du (pseudo-kode):

    foreach( word(w) in record(r) ) {
      if(w is not in stopwords) {
        if( w does not exist in dictionary) {
          insert w to dictionary at w.id
        }
        insert (r.id, w.id) into inverted_index
      }
    }
Mere om stopord:

I stedet for at bruge en specifik stopordsliste kunne 'hvis(w er ikke i stopord)'-testen træffe andre beslutninger enten i stedet for eller som et supplement til din liste over uacceptable ord.

Din applikation ønsker måske at bortfiltrere alle ord på mindre end 4 tegn eller kun inkludere ord fra et foruddefineret sæt.

Ved at oprette dit eget omvendte indeks får du langt større og finere kontrol over søgning.

Trin 3. Forespørg på det omvendte indeks ved hjælp af SQL

Dette trin afhænger virkelig af, hvordan du forventer, at forespørgsler sendes til dit indeks.

Hvis forespørgsler skal 'hardkodes', kan du blot selv oprette select-sætningen, eller hvis du skal understøtte brugerindtastede forespørgsler, skal du konvertere det forespørgselssprog, du vælger, til en SQL-sætning (typisk ved hjælp af en simpel parser).

Hvis du antager, at du ønsker at hente alle dokumenter, der matcher den logiske forespørgsel '(ord1 OG ord2) ELLER ord3', kan en mulig fremgangsmåde være:

CREATE TEMPORARY TABLE temp_results ( rec_id int, count int ) AS 
    ( SELECT rec_id, COUNT(rec_id) AS count 
      FROM invert AS I, dict AS D 
      WHERE I.word_id=D.id AND (D.word='word1' OR D.word='word2') 
      GROUP BY I.rec_id 
      HAVING count=2
    ) 
    UNION (
      SELECT rec_id, 1 AS count 
      FROM invert AS I, dict AS D
      WHERE I.word_id=D.id AND D.word='word3'
    );

SELECT DISTINCT rec_id FROM temp_results;

DROP TABLE temp_results;

BEMÆRK:Dette er kun en første omgang fra toppen af ​​mit hoved. Jeg er overbevist om, at der er mere effektive måder at konvertere et boolesk forespørgselsudtryk til en effektiv SQL-sætning og hilser alle forslag til forbedring velkommen.

For at søge efter sætninger skal du føje et felt til det omvendte indeks for at repræsentere den position, ordet optrådte i dets registrering, og indregne det i din SELECT.

Og endelig skal du opdatere dit omvendte indeks, når du tilføjer nye poster eller sletter gamle.

Sidste ord

"Fuld tekstsøgning" falder ind under et meget stort forskningsområde kendt som "Informationssøgning" eller IR, og der er mange bøger om emnet, herunder

Tjek Amazon for mere.

Bemærkninger

Sådan bruger du din egen liste over stopord i MySQL

Sådan bruger du din egen stopordsliste i MySQL:

  1. Opret din egen liste over stopord, et ord pr. linje, og gem det på en kendt placering på din server, sig:/usr/local/lib/IR/stopwords.txt

  2. Rediger my.cnf for at tilføje eller opdatere følgende linjer:
        [mysqld]  
        ft_min_word_len=1    
        ft_max_word_len=40  
        ft_stopword_file=/usr/local/lib/IR/stopwords.txt
    

    som vil indstille minimums- og maksimumlængden af ​​lovlige ord til henholdsvis 1 og 40, og fortælle mysqld, hvor du kan finde din tilpassede liste over stopord.

    (Bemærk:standard ft_max_word_len er 84, hvilket jeg mener er ret overdrevet og kan forårsage, at rækker af strenge, der ikke er rigtige ord, bliver indekseret.)

  3. Genstart mysqld

  4. Slip og genskab alle fuldtekstrelaterede indekser



  1. Hvordan tager man MySQL database backup ved hjælp af MySQL Workbench?

  2. Docker Laravel Mysql:kunne ikke finde driveren

  3. SQLiteConstraintException-fejl vises efter start af hver aktivitet

  4. Hvor er PostgreSQL-logfilerne på macOS?