2013-04-25 18 views
9

Mam "dokumenty" (activerecords) z atrybutem zwanym dewiacjami. Atrybut ma wartości takie jak "Bin X" "Bin $" "Bin q" "Bin%" itp.Symbole w ciągu kwerendy dla elasticsearch

Próbuję użyć wyszukiwarki opon/elastycznej, aby przeszukać atrybut. Używam analizatora białych znaków do indeksowania atrybutu odchylenia. Oto mój kod do tworzenia indeksów:

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 

Wyszukiwanie wydaje się działać poprawnie, gdy ciąg zapytania nie zawiera znaków specjalnych. Na przykład Bin X zwróci tylko te rekordy, które zawierają w sobie słowa Bin i X. Jednak poszukiwanie czegoś takiego jak Bin $ lub Bin % pokazuje wszystkie wyniki, które zawierają słowo Bin prawie ignorując symbol (wyniki z symbolem pokazują się wyżej w wynikach wyszukiwania, które nie są wynikiem).

Oto metoda wyszukiwania Stworzyłem

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

i oto jak buduję formularz wyszukiwarki:

<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

Nie tylko uciec od postaci mają znaczenie dla Lucene z ukośnikiem odwrotnym? Oczywiście w łańcuchu Ruby potrzebny jest podwójny ukośnik odwrotny \\, aby uciec przed postacią ruby, zanim trafi ona w interfejs API Elastic Search. Nie próbowałem Tyru, więc nie wiem, czy działa w twoim świecie. FYI, tutaj jest szybkie odniesienie do dotkniętych postaci: http://docs.lucidworks.com/display/lweug/Escaping+Special+Syntax+Characters – Phil

+0

Nie sądzę, że to jest problem, ponieważ zapytania Bin $ lub Bin% mają one wpływ, ale nie są wymienione w powyższym linku jako znak specjalny. – Arnob

+0

Wiem z własnego doświadczenia pełnego przeszukiwania tekstu w bazach danych (Oracle, jak mi się zdawało, i MySQL dla testów LIKE w polach varchar lub text), że% jest znakiem "dopasuj wszystko". Być może powyższy link jest niekompletny lub może nie mieć związku z Twoim problemem. Czy próbowałeś uciekać, aby sprawdzić, czy to rozwiąże problem? – Phil

Odpowiedz

24

można zdezynfekować swój ciąg kwerendy. Oto środek dezynfekujący, który działa na wszystko, co próbowałem rzucić:

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

Potrzebowałem dodać przedni ukośnik również do tablicy 'escaped_characters'. 'escaped_characters = Regexp.escape ('\\ + - & |!() {} []^~ *?: \ /')' jak to było zerwanie dla łańcuchów z ukośnikiem w przód. – rubyprince

+0

To dziwne, ponieważ '/' nie jest specjalną postacią w Lucene: http://lucene.apache.org/core/old_versioned_docs/versions/2_9_1/queryparsersyntax.html#Escaping%20Special%20Characters –

+0

Witam, zobacz http://50.16.250.253:9200/locations/location/_search?q=123%2F345 .. Myślę, że to powoduje błąd, ponieważ '/' znajduje się wewnątrz łańcucha ... kiedy ucieknę z '\\', błąd został rozwiązany, http://50.16.250.253:9200/locations/location/_search?q=123%5C%2F345 – rubyprince