125
Como NÃO fazer pesquisas usando LIKE Fabio Akita @akitaonrails

Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Embed Size (px)

DESCRIPTION

Palestra para o Evento Dev in Santos, em Novembro/2013. Demonstrar como a maioria implementa search errado, como é amplo o campo de classificação e pesquisa de textos e documentos e as melhores soluções do mercado hoje.

Citation preview

Page 1: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Como NÃO fazer pesquisas usando LIKE

Fabio Akita @akitaonrails

Page 2: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

www.codeminer42.com

Page 3: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

www.codeminer42.com

Page 4: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

www.codeminer42.com

Page 5: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

www.codeminer42.com

Page 6: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

www.codeminer42.com

Page 7: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

www.codeminer42.com

Page 8: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

www.codeminer42.com

Page 9: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

www.codeminer42.com

Page 10: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

www.codeminer42.com

Page 11: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

www.codeminer42.com

Page 12: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

www.codeminer42.com

Page 13: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

www.codeminer42.com

Page 14: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 15: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Search está em todos os lugares

Page 16: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

SELECT * FROM PRODUCTS WHERE NAME LIKE '%Camisetas%' AND DESCRIPTION LIKE '%Camisetas%' AND NAME NOT LIKE '%Calças%' AND DESCRIPTION NOT LIKE '%Calças%'

Page 17: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 18: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Camisetas INDEX SEEK Rápido

Page 19: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Camisetas INDEX SEEK Rápido

Camisetas% INDEX SCAN Quase Rápido

Page 20: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Camisetas INDEX SEEK Rápido

Camisetas% INDEX SCAN Quase Rápido

%Camisetas% TABLE SCAN Indo pra trás

Page 21: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Índices não vão te ajudar

Page 22: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 23: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

wp-includes/taxonomy.php (1256 até 1545)

WordPress

Page 24: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

<?php function get_terms($taxonomies, $args = '') {   ...   if ( !empty($name__like) ) {     $name__like = like_escape( $name__like );     $where .= $wpdb->prepare( " AND t.name LIKE %s",       '%' . $name__like . '%' );   }      if ( ! empty( $description__like ) ) {     $description__like = like_escape( $description__like );     $where .= $wpdb->prepare( " AND tt.description LIKE %s",       '%' . $description__like . '%' );   }   ...      if ( ! empty( $search ) ) {     $search = like_escape( $search );     $where .= $wpdb->prepare( ' AND ((t.name LIKE %s) OR (t.slug LIKE %s))',       '%' . $search . '%', '%' . $search . '%' );   }   ... } ?>

Page 25: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

AbstractHelper.php

Magento

Page 26: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

<?php

public function getCILike($field, $value, $options = array()) {

  $quotedField = $this->_getReadAdapter()->quoteIdentifier($field);   return new \Zend_Db_Expr($quotedField . ' LIKE ' .     $this->addLikeEscape($value, $options)); }

?>

Page 27: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 28: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Rankeamento, Relevância

Page 29: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Rankeamento, Relevância

Frases, Proximidade, Intervalos

Page 30: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Rankeamento, Relevância

Frases, Proximidade, Intervalos

Sinônimos, "Stemmer"

Page 31: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Rankeamento, Relevância

Frases, Proximidade, Intervalos

Sinônimos, "Stemmer"

“More Like This"

Page 32: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Rankeamento, Relevância

Frases, Proximidade, Intervalos

Sinônimos, "Stemmer"

“More Like This"

“Did you mean …?"

Page 33: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Rankeamento, Relevância

Frases, Proximidade, Intervalos

Sinônimos, "Stemmer"

“More Like This"

“Did you mean …?"

Faceting (Terms, Geolocation, etc)

Page 34: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 35: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Pesquisa Não-Estruturada

Page 36: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Pesquisa Não-EstruturadaSugestões

Page 37: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Pesquisa Não-Estruturada

Ordenação

Sugestões

Page 38: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Pesquisa Não-Estruturada

Terms Facet

Ordenação

Sugestões

Page 39: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Pesquisa Não-Estruturada

Terms Facet

Ordenação

Agregação

Sugestões

Page 40: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Pesquisa Não-Estruturada

Terms Facet

Ordenação

Paginação

Agregação

Sugestões

Page 41: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

SELECT * FROM PRODUCTS WHERE MATCH (NAME, DESCRIPTION) AGAINST ('+Camisetas -Calças' IN BOOLEAN MODE)

Page 42: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

CatalogSearch/Model/Resource/Helper.php

Magento

Page 43: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

<?php

public function chooseFulltext($table, $alias, $select) {

  $field = new \Zend_Db_Expr(     'MATCH (' . $alias . '.data_index) AGAINST (:query IN BOOLEAN MODE)');

  $select->columns(array('relevance' => $field));   return $field; }

?>

Page 44: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

SELECT * FROM PRODUCTS WHERE CONTAINS( (NAME, DESCRIPTION), 'Camisetas AND NOT Calças')

Page 45: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

SELECT * FROM PRODUCTS WHERE TO_TSVECTOR(NAME || '' || DESCRIPTION) @@ TO_TSQUERY('Camisetas &! Calças')

Page 46: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 47: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 48: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 49: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Cadeias de Markov

Page 50: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Cadeias de Markov

Índices Invertidos

Page 51: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Cadeias de Markov

Índices Invertidos

Vector Space Model

Page 52: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Cadeias de Markov

Índices Invertidos

Vector Space Model

Okapi BM25

Page 53: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 54: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

http://u.akita.ws/vsm_example (Exemplo Simplificado)

Vector Space Model

Page 55: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

d1 “new york times"

d2 “new york post"

d3 “los angeles times"

Page 56: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

angeles log2(3/1)=1.584

los log2(3/1)=1.584

new log2(3/2)=0.584

post log2(3/1)=1.584

times log2(3/2)=0.584

york log2(3/2)=0.584

Page 57: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

angeles los new post times york

d1 0 0 1 0 1 1

d2 0 0 1 1 0 1

d3 1 1 0 0 1 0

Page 58: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

angeles los new post times york

d1 0 0 0.584 0 0.584 0.584

d2 0 0 0.584 1.584 0 0.584

d3 1.584 1.584 0 0 0.584 0

Page 59: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

angeles los new post times york

q 0 0 (2/2)*0.584= 0.584 0 (1/2)*0.584=

0.292 0

q = “new new times"

Page 60: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Distância d1 sqrt(0.584^2+0.584^2+0.584^2) 1.011

Distância d2 sqrt(0.584^2+1.584^2+0.584^2) 1.786

Distância d3 sqrt(1.584^2+1.584^2+0.584^2) 2.316

Distância q sqrt(0.584^2+0.292^2) 0.652

Page 61: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

cosSim(d1,q) (0*0+0*0+0.584*0.584+0*0+0.584*0.292+0.584*0) / (1.011*0.652) 0.776

cosSim(d2,q) (0*0+0*0+0.584*0.584+1.584*0+0*0.292+0.584*0) / (1.786*0.652) 0.292

cosSim(d3,q) (1.584*0+1.584*0+0*0.584+0*0+0.584*0.292+0*0) / (2.316*0.652) 0.112

Page 62: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Douglass Cutting

LuceneNutch

Hadoop!

TikaSolr

ElasticSearch

Page 63: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Apache Lucene

150GB/hora 20%-30% tamanho do índice

Page 64: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 65: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 66: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

HTML, XHTML, OOXML, ODF, XML, RSS, OLE2, iWorks (Pages, Numbers, Keynote), PDF, EPUB, RTF, Commons Compress (ar, cpio, Unix dump, tar, zip, gzip, XZ, Pack200, bzip2, 7z, arj e lzma), Audio (javax.sound, MIDI, Mp3), Image (javax.imageio, Tiff, Jpeg), Video (FLV, Flash), Mail (Mbox, RFC822), DWG, Font (TrueType), HDF, e plugins.

Page 67: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

InputStream is = new BufferedInputStream( new FileInputStream( new File("sample.pdf"))); !Parser parser = new AutoDetectParser(); ContentHandler handler = new BodyContentHandler( System.out); !Metadata metadata = new Metadata(); !parser.parse(is, handler, metadata, new ParseContext()); !for (String name : metadata.names()) { String value = metadata.get(name); ! if (value != null) { System.out.println("Metadata Name: " + name); System.out.println("Metadata Value: " + value); } }

Page 68: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 69: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 70: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 71: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 72: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

http://localhost:8983/solr/query?q=title:black

Page 73: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

http://localhost:8983/solr/query? q=*:* &fl=id,title,series_s,pubyear_i &sort=pubyear_i desc &group=true &group.main=true &group.field=series_s &facet=true &facet.field=cat

Page 74: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

curl "http://localhost:8983/solr/update/extract?literal.id=doc5&defaultField=text” --data-binary @tutorial.html -H 'Content-type:text/html'

Page 75: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 76: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 77: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 78: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 79: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 80: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 81: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 82: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 83: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 84: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 85: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 86: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 87: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 88: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 89: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Solr ElasticSearch

Page 90: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Solr ElasticSearch

Coordination ZooKeeper Zen Discovery

Page 91: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Solr ElasticSearch

Coordination ZooKeeper Zen Discovery

Shard Splitting Sim Não

Page 92: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Solr ElasticSearch

Coordination ZooKeeper Zen Discovery

Shard Splitting Sim Não

Automatic Shard Rebalancing Não Sim

Page 93: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Solr ElasticSearch

Coordination ZooKeeper Zen Discovery

Shard Splitting Sim Não

Automatic Shard Rebalancing Não Sim

Schema + / - Sim

Page 94: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Solr ElasticSearch

Coordination ZooKeeper Zen Discovery

Shard Splitting Sim Não

Automatic Shard Rebalancing Não Sim

Schema + / - Sim

Nested Typing Não Sim

Page 95: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Solr ElasticSearch

Coordination ZooKeeper Zen Discovery

Shard Splitting Sim Não

Automatic Shard Rebalancing Não Sim

Schema + / - Sim

Nested Typing Não Sim

Queries Key / Value JSON

Page 96: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Solr ElasticSearch

Coordination ZooKeeper Zen Discovery

Shard Splitting Sim Não

Automatic Shard Rebalancing Não Sim

Schema + / - Sim

Nested Typing Não Sim

Queries Key / Value JSON

Distributed Group By Sim Não

Page 97: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Solr ElasticSearch

Coordination ZooKeeper Zen Discovery

Shard Splitting Sim Não

Automatic Shard Rebalancing Não Sim

Schema + / - Sim

Nested Typing Não Sim

Queries Key / Value JSON

Distributed Group By Sim Não

Percolation Queries Não Sim

Page 98: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 99: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 100: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 101: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 102: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 103: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 104: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 105: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Setup

cd ~ sudo apt-get update

sudo apt-get install openjdk-7-jre-headless -y

### http://www.elasticsearch.org/download/

wget https://download.elasticsearch.org/elasticsearch/elasticsearch/

elasticsearch-0.90.7.deb

sudo dpkg -i elasticsearch-0.90.7.deb sudo service elasticsearch start

Page 106: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Setup

# Bonsai heroku addons:add bonsai heroku config:add ELASTICSEARCH_URL=`heroku config:get BONSAI_URL` !# Found heroku addons:add foundelasticsearch heroku config:add ELASTICSEARCH_URL=`heroku config:get FOUNDELASTICSEARCH_URL` !# SearchBox heroku addons:add searchbox:starter heroku config:add ELASTICSEARCH_URL=`heroku config:get SEARCHBOX_URL` !# reindex heroku run rake searchkick:reindex CLASS=Product

Page 107: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Setup

# Gemfile - bundle install gem "searchkick" !# app/models/product.rb class Product < ActiveRecord::Base searchkick end !# config/initializers/elasticsearch.rb ENV["ELASTICSEARCH_URL"] = "http://username:[email protected]" !# no shell rails r "Product.reindex"

Page 108: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

# Search simples products = Product.search "Camisetas" products.each do |product| puts product.name end

Page 109: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

# Search simples products = Product.search "Camisetas" products.each do |product| puts product.name end

# Search com campos Product.search "Camisetas", fields: [:name, :description] where: { in_stock: true, expires_at: {gt: 1.week.from_now}, or: [ [{in_stock: true}, {backordered: true}] ] }, order: {_score: :desc}, # relevant first limit: 10, offset: 50 # , page: params[:page], per_page: 20

Page 110: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

# Sinonimos class Product < ActiveRecord::Base searchkick synonyms: [ ["pc", "computador pessoal"], ["word", "microsoft office"] ] end

Page 111: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

# Sinonimos class Product < ActiveRecord::Base searchkick synonyms: [ ["pc", "computador pessoal"], ["word", "microsoft office"] ] end

# Sugestões class Product < ActiveRecord::Base searchkick suggest: ["name"] end !products = Product.search "cold miner ", suggest: true products.suggestions # ["codeminer"]

Page 112: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 113: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

class City < ActiveRecord::Base searchkick autocomplete: ["name"] end !City.search "Sao P", autocomplete: true

Page 114: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

# app/controllers/cities_controller.rb class CitiesController < ApplicationController def autocomplete render json: City.search(params[:query], autocomplete: true, limit: 10).map(&:name) end end

Page 115: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

# app/controllers/cities_controller.rb class CitiesController < ApplicationController def autocomplete render json: City.search(params[:query], autocomplete: true, limit: 10).map(&:name) end end

# partial <input type="text" id="query" name="query" /> !<script src="jquery.js"></script> <script src="typeahead.js"></script> <script> $("#query").typeahead({ name: "city", remote: "/cities/autocomplete?query=%QUERY" }); </script>

Page 116: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 117: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

products = Product.search "GPS", facets: [:type, :brand, :screen_size] puts products.facets

Page 118: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 119: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

class City < ActiveRecord::Base searchkick locations: ["location"] ! def search_data attributes.merge location: [latitude, longitude] end end !City.search "Codemi", where: { location: {near: [-23, -46], within: "10mi" } } # ou 16km

Page 120: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

Próximos Capítulos

Page 121: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 122: Dev in Santos - Como NÃO fazer pesquisas usando LIKE
Page 123: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

SELECT … LIKE ‘%'

Page 124: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

SELECT … LIKE ‘%'

Page 125: Dev in Santos - Como NÃO fazer pesquisas usando LIKE

OBRIGADO!slideshare.net/akitaonrailscodeminer42.com@akitaonrails