2016-02-05 6 views
9

Di seguito è riportato il mio codice per generare l'indice utilizzando elasticsearch.Index viene generato correttamente. Fondamentalmente lo sto utilizzando per generare autosuggest a seconda del nome del film, nome dell'attore e gener.Elasticsearch corrisponde alla sottostringa in php

Ora la mia richiesta è, ho bisogno di abbinare sottostringa con particolare field.This sta funzionando benissimo se uso $params['body']['query']['wildcard']['field'] = '*sub_word*';. (Vale a dire la ricerca di 'a' dà 'tom Kruz', ma la ricerca di 'tom kr' non restituisce alcun risultato) .

Ciò corrisponde solo a una parola specifica in stringa. Voglio corrispondere alla sottostringa contenente più parole (ad esempio 'tom kr' dovrebbe restituire 'tom kruz').

Ho trovato pochi documenti, dicendo che sarà possibile utilizzare 'ngram'. Ma non so, come dovrei implementarlo nel mio codice, perché sto usando configurazioni basate su array per elasticsearch e tutti i documenti di supporto menzionano la configurazione in json fromat.

prega di aiuto.

require 'vendor/autoload.php'; 

$client = \Elasticsearch\ClientBuilder::create() 
->setHosts(['http://localhost:9200'])->build(); 

/*************Index a document****************/ 
$params = ['body' => []]; 
$j = 1; 
for ($i = 1; $i <= 100; $i++) { 
    $params['body'][] = [ 
     'index' => [ 
      '_index' => 'pvrmod', 
      '_type' => 'movie', 
      '_id' => $i 
     ] 
    ]; 
    if ($i % 10 == 0) 
     $j++; 
    $params['body'][] = [ 
     'title' => 'salaman khaan'.$j, 
     'desc' => 'salaman khaan description'.$j, 
     'gener' => 'movie gener'.$j, 
     'language' => 'movie language'.$j, 
     'year' => 'movie year'.$j, 
     'actor' => 'movie actor'.$j, 
    ]; 

    // Every 10 documents stop and send the bulk request 
    if ($i % 10 == 0) { 
     $responses = $client->bulk($params); 

     // erase the old bulk request 
     $params = ['body' => []]; 

     unset($responses); 
    } 
} 

// Send the last batch if it exists 
if (!empty($params['body'])) { 
    $responses = $client->bulk($params); 
} 

risposta

5

Tentare di creare questo JSON

{ 
"query": { 
    "filtered": { 
     "query": { 
      "bool": { 
       "should": [ 
        { 
         "wildcard": { 
          "field": { 
           "value": "tom*", 
           "boost": 1 
          } 
         } 
        }, 
        { 
         "field": { 
          "brandname": { 
           "value": "kr*", 
           "boost": 1 
          } 
         } 
        }, 
       ] 
      } 
     } 
    } 
} 

Si può esplodere il termine di ricerca

$searchTerms = explode(' ', 'tom kruz'); 

e quindi creare il jolly per ognuno

foreach($searchTerms as $searchTerm) { 
//create the new array 
} 
+0

Caro Costa, Grazie per la risposta. Ma solo una domanda, sei sicuro, eseguire la ricerca con caratteri jolly per singole parole mi darà risultati più pertinenti che corrispondono alla sottostringa multiword? –

6

Il problema qui menzogna s nel fatto che Elasticsearch costruisce un indice invertito. Supponendo che tu usi l'analizzatore standard, la frase "tom kruz è una pistola in alto" viene divisa in 6 gettoni: tom - kruz - is - a - top - gun. Questi token vengono assegnati al documento (con alcuni metadati relativi alla posizione, ma lasciamo per ora il lato).

Se si desidera eseguire una corrispondenza parziale, è possibile, ma solo sui token separati, non oltre il limite dei token come si desidera. Il suggerimento per dividere la stringa di ricerca e costruire una query con caratteri jolly da queste stringhe è un'opzione.

Un'altra opzione potrebbe effettivamente utilizzare un filtro token ngram o edge_ngram. Quello che farebbe (al momento dell'indice) sta creando quei token parziali (come t - to - tom - ... - k - kr - kru - kruz - ...) in anticipo e puoi semplicemente inserire 'tom kr' nella tua ricerca (corrisponde) e corrisponderebbe. Attenzione però: questo gonfierà il tuo indice (come puoi vedere, memorizzerà MOLTI più token), hai bisogno di custom analysers e probabilmente un bel po 'di conoscenza sui tuoi mapping.

In generale, la rotta (edge_) ngram è una buona idea solo per cose come il completamento automatico, non solo per qualsiasi campo di testo nel tuo indice. Ci sono alcuni modi per aggirare il tuo problema, ma la maggior parte riguarda la creazione di funzionalità separate per rilevare le parole errate e provare a suggerire i termini giusti per farlo.