2013-04-25 9 views
9

I "documenti" (activerecords) con un attributo chiamato deviazioni. L'attributo ha valori come "Bin X" "Bin $" "Bin q" "Bin%" ecc.Simboli in stringa di query per elasticsearch

Sto cercando di utilizzare pneumatico/elasticsearch per cercare l'attributo. Sto usando l'analizzatore di spazi bianchi per indicizzare l'attributo di deviazione. Ecco il mio codice per la creazione degli indici:

settings :analysis => { 
    :filter => { 
     :ngram_filter => { 
     :type => "nGram", 
     :min_gram => 2, 
     :max_gram => 255 
     }, 
     :deviation_filter => { 
     :type => "word_delimiter", 
     :type_table => ['$ => ALPHA'] 
     } 
    }, 
    :analyzer => { 
     :ngram_analyzer => { 
     :type => "custom", 
     :tokenizer => "standard", 
     :filter => ["lowercase", "ngram_filter"] 
     }, 
     :deviation_analyzer => { 
     :type => "custom", 
     :tokenizer => "whitespace", 
     :filter => ["lowercase"] 
     } 
    } 
    } do 
    mapping do 
     indexes :id, :type => 'integer' 
     [:equipment, :step, :recipe, :details, :description].each do |attribute| 
     indexes attribute, :type => 'string', :analyzer => 'ngram_analyzer' 
     end 
     indexes :deviation, :analyzer => 'whitespace' 
    end 
    end 

La ricerca sembra funzionare bene quando la stringa di query non contiene caratteri speciali. Ad esempio, Bin X restituirà solo quei record che contengono le parole Bin E X. Tuttavia, la ricerca di qualcosa come Bin $ o Bin % mostra tutti i risultati che hanno la parola Bin quasi ignorando il simbolo (i risultati con il simbolo appaiono più in alto nella ricerca che risulta senza).

Ecco il metodo di ricerca che ho creato

def self.search(params) 
    tire.search(load: true) do 
     query { string "#{params[:term].downcase}:#{params[:query]}", default_operator: "AND" } 
     size 1000 
    end 
end 

e ecco come lo sto costruendo il modulo di ricerca:

<div> 
    <%= form_tag issues_path, :class=> "formtastic issue", method: :get do %> 
     <fieldset class="inputs"> 
     <ol> 
      <li class="string input medium search query optional stringish inline"> 
       <% opts = ["Description", "Detail","Deviation","Equipment","Recipe", "Step"] %> 
       <%= select_tag :term, options_for_select(opts, params[:term]) %> 
       <%= text_field_tag :query, params[:query] %> 
       <%= submit_tag "Search", name: nil, class: "btn" %> 
      </li> 
     </ol> 
     </fieldset> 
    <% end %> 
</div> 
+0

Non basta sfuggire ai personaggi che hanno un significato per Lucene con un backslash? Ovviamente, in una stringa di Ruby è necessario un doppio backslash \\ per sfuggire al carattere rubino prima che colpisca l'api di Elastic Search. Non ho provato Tiro, quindi non so se funzioni nel tuo mondo. Cordiali saluti, ecco un rapido riferimento ai personaggi interessati: http://docs.lucidworks.com/display/lweug/Escaping+Special+Syntax+Characters – Phil

+0

Non penso che questo sia il problema, perché le query Bin $ o Bin% sono interessati, ma non sono elencati nel link sopra come carattere speciale. – Arnob

+0

Conosco la mia esperienza di ricerca full text nei database (Oracle penso che fosse, e MySQL per i test LIKE in varchar o nei campi di testo) che% è un carattere 'match everything'. Forse quel link sopra è incompleto, o forse non è pertinente al tuo problema. Hai provato a scappare per vedere se questo risolve il problema? – Phil

risposta

24

È possibile disinfettare il tuo stringa di query. Ecco un disinfettante che funziona per tutto ciò che ho provato a lanciarlo:

def sanitize_string_for_elasticsearch_string_query(str) 
    # Escape special characters 
    # http://lucene.apache.org/core/old_versioned_docs/versions/2_9_1/queryparsersyntax.html#Escaping Special Characters 
    escaped_characters = Regexp.escape('\\/+-&|!(){}[]^~*?:') 
    str = str.gsub(/([#{escaped_characters}])/, '\\\\\1') 

    # AND, OR and NOT are used by lucene as logical operators. We need 
    # to escape them 
    ['AND', 'OR', 'NOT'].each do |word| 
    escaped_word = word.split('').map {|char| "\\#{char}" }.join('') 
    str = str.gsub(/\s*\b(#{word.upcase})\b\s*/, " #{escaped_word} ") 
    end 

    # Escape odd quotes 
    quote_count = str.count '"' 
    str = str.gsub(/(.*)"(.*)/, '\1\"\3') if quote_count % 2 == 1 

    str 
end 

params[:query] = sanitize_string_for_elasticsearch_string_query(params[:query]) 
+2

Avevo bisogno di aggiungere la barra in avanti anche alla matrice 'escaped_characters'. 'escaped_characters = Regexp.escape ('\\ + - & |!() {} []^~ *?: \ /')' come si è spezzato per le stringhe con barra in avanti. – rubyprince

+0

Questo è strano poiché '/' non è un personaggio speciale in Lucene: http://lucene.apache.org/core/old_versioned_docs/versions/2_9_1/queryparsersyntax.html#Escaping%20Special%20Characters –

+0

Ciao, per favore vedi http://50.16.250.253:9200/locations/location/_search?q=123%2F345 .. Penso che questo stia dando un errore, perché '/' è all'interno della stringa ... quando esco con un '\\', il l'errore è stato risolto, http://50.16.250.253:9200/locations/location/_search?q=123%5C%2F345 – rubyprince