2013-04-25 18 views
9

Sapmalar denilen bir niteliğe sahip "belgeler" (activerecords) var. Öznitelik "Bin X" "Bin $" "Bin q" "Bin%" gibi değerlere sahiptir.Elasticsearch için sorgu dizesindeki simgeler

Öznitelikte arama yapmak için lastik/elasticsearch kullanmaya çalışıyorum. Sapma özniteliğini indekslemek için beyaz boşluk analizcisini kullanıyorum. İşte benim kod dizinleri oluşturma içindir:

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 

arama sorgu dizesi hiçbir özel karakterler içerdiğinde iyi iş gibi görünüyor. Örneğin, Bin X yalnızca içlerinde Bin AND X sözcükleri bulunan kayıtları döndürecektir. Ancak, Bin $ veya Bin % gibi bir şeyi aramak, neredeyse sembolü göz ardı ederek Bin kelimesine sahip tüm sonuçları gösterir (sonuçta, sonuçta arama, sonuçta olmayan aramada daha yüksek görünür). İşte

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

oluşturduk arama yöntemidir ve burada arama formunu inşa ediyorum nasıl:

<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

Sadece karakterlerin Lucene için ters eğik çizgi ile bir anlam ifade etmiyor musunuz? Elbette, bir Ruby dizgisinde, Elastic Search api'ye ulaşmadan önce yakut karakterinden kaçmak için bir çift ters eğik çizgi gerekir. Lastiği denemedim, bu yüzden senin dünyanda çalışıp çalışmadığını bilmiyorum. FYI, burada etkilenen karakterlere hızlı bir başvuru: http://docs.lucidworks.com/display/lweug/Escaping+Special+Syntax+Characters – Phil

+0

Sorunun Bin $ veya Bin% olduğu için bu sorun olduğunu sanmıyorum etkilenir, ancak yukarıdaki bağlantıda özel bir karakter olarak listelenmez. – Arnob

+0

Veritabanlarında tam metin arama deneyimlerimden (Oracle'ın sanırım var olduğunu ve varchar veya metin alanlarında LIKE için MySQL testleri)% 'nin bir' her şeyi eşleştir 'karakteri olduğunu biliyorum. Belki de yukarıdaki bağlantı eksiktir veya belki de sizin sorununuzla alakalı değildir. Sorunun çözülüp çözülmediğini görmek için kaçmayı denediniz mi? – Phil

cevap

24

Sen sorgu dizesi sterilize edebilirsiniz. İşte attığım her şey için çalışan bir dezenfektan:

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

Ayrıca "escaped_characters" dizisine de eğik çizgi eklemem gerekiyordu. 'escaped_characters = Eğik çizgi ile dizgileri koparken Regexp.escape ('\\ + - & |!() {} []^~ *?: \ /'). – rubyprince

+0

Lucene'de özel bir karakter olmadığından bu garipti: http://lucene.apache.org/core/old_versioned_docs/versions/2_9_1/queryparsersyntax.html#Escaping%20Special%20Characters –

+0

Merhaba, lütfen http:/adresine bakın. /50.16.250.253:9200/locations/location/_search?q=123%2F345 .. Bunun bir hata verdiğini düşünüyorum, çünkü '/' dizenin içinde… ben bir '\\' ile kaçtığımda hata çözüldü, http://50.16.250.253:9200/locations/location/_search?q=123%5C%2F345 – rubyprince

İlgili konular