2013-03-15 10 views
12

Mi piacerebbe essere in grado di abbinare una ricerca di più parole su più campi in cui ogni parola cercata è contenuta in qualsiasi dei campi, qualsiasi combinazione. Il problema è che vorrei evitare di utilizzare query_string.Multi-field, multi-word, match senza query_string

curl -X POST "http://localhost:9200/index/document/1" -d '{"id":1,"firstname":"john","middlename":"clark","lastname":"smith"}' 
curl -X POST "http://localhost:9200/index/document/2" -d '{"id":2,"firstname":"john","middlename":"paladini","lastname":"miranda"}' 

Vorrei che la ricerca di 'John Smith' per indicare solo documento 1. La seguente interrogazione fa quello che mi serve, ma avrei preferito evitare di usare query_string nel caso in cui i passi utente "o", "E" e uno qualsiasi degli altri parametri avanzati.

curl -X GET 'http://localhost:9200/index/_search?per_page=10&pretty' -d '{ 
    "query": { 
    "query_string": { 
     "query": "john smith", 
     "default_operator": "AND", 
     "fields": [ 
     "firstname", 
     "lastname", 
     "middlename" 
     ] 
    } 
    } 
}' 
+0

Continuo a venire a questa domanda più e più volte. Grande domanda sempreverde! –

risposta

23

Quello che stai cercando è il multi-match query, ma non funziona nel modo che preferisci.

Confrontare l'output di validate per multi_match rispetto a query_string.

multi_match (con operatore and) farà in modo che esistano tutti i termini in almeno un campo:

curl -XGET 'http://127.0.0.1:9200/_validate/query?pretty=1&explain=true' -d ' 
{ 
    "multi_match" : { 
     "operator" : "and", 
     "fields" : [ 
     "firstname", 
     "lastname" 
     ], 
     "query" : "john smith" 
    } 
} 
' 

# { 
# "_shards" : { 
#  "failed" : 0, 
#  "successful" : 1, 
#  "total" : 1 
# }, 
# "explanations" : [ 
#  { 
#   "index" : "test", 
#   "explanation" : "((+lastname:john +lastname:smith) | (+firstname:john +firstname:smith))", 
#   "valid" : true 
#  } 
# ], 
# "valid" : true 
# } 

Mentre query_string (con default_operator AND) controllerà che esiste ogni termine almeno un campo:

curl -XGET 'http://127.0.0.1:9200/_validate/query?pretty=1&explain=true' -d ' 
{ 
    "query_string" : { 
     "fields" : [ 
     "firstname", 
     "lastname" 
     ], 
     "query" : "john smith", 
     "default_operator" : "AND" 
    } 
} 
' 

# { 
# "_shards" : { 
#  "failed" : 0, 
#  "successful" : 1, 
#  "total" : 1 
# }, 
# "explanations" : [ 
#  { 
#   "index" : "test", 
#   "explanation" : "+(firstname:john | lastname:john) +(firstname:smith | lastname:smith)", 
#   "valid" : true 
#  } 
# ], 
# "valid" : true 
# } 

in modo da avere un paio di scelte per ottenere quello che stai cercando:

  1. preparse i termini di ricerca, per rimuovere le cose come jolly, ecc, prima di utilizzare il query_string

  2. preparse i termini di ricerca per estrarre ogni parola, quindi generare un multi_match di query per parola

  3. Uso index_name nella vostra mappatura per i campi dei nomi per indicizzare i loro dati in un singolo campo, che è possibile utilizzare per la ricerca. (Come il proprio personalizzato all campo):

Come segue:

curl -XPUT 'http://127.0.0.1:9200/test/?pretty=1' -d ' 
{ 
    "mappings" : { 
     "test" : { 
     "properties" : { 
      "firstname" : { 
       "index_name" : "name", 
       "type" : "string" 
      }, 
      "lastname" : { 
       "index_name" : "name", 
       "type" : "string" 
      } 
     } 
     } 
    } 
} 
' 

curl -XPOST 'http://127.0.0.1:9200/test/test?pretty=1' -d ' 
{ 
    "firstname" : "john", 
    "lastname" : "smith" 
} 
' 

curl -XGET 'http://127.0.0.1:9200/test/test/_search?pretty=1' -d ' 
{ 
    "query" : { 
     "match" : { 
     "name" : { 
      "operator" : "and", 
      "query" : "john smith" 
     } 
     } 
    } 
} 
' 

# { 
# "hits" : { 
#  "hits" : [ 
#   { 
#    "_source" : { 
#    "firstname" : "john", 
#    "lastname" : "smith" 
#    }, 
#    "_score" : 0.2712221, 
#    "_index" : "test", 
#    "_id" : "VJFU_RWbRNaeHF9wNM8fRA", 
#    "_type" : "test" 
#   } 
#  ], 
#  "max_score" : 0.2712221, 
#  "total" : 1 
# }, 
# "timed_out" : false, 
# "_shards" : { 
#  "failed" : 0, 
#  "successful" : 5, 
#  "total" : 5 
# }, 
# "took" : 33 
# } 

Nota però che firstname e lastname non è più consultabile sono in modo indipendente. I dati per entrambi i campi sono stati indicizzati in name.

Si potrebbe usare multi-fields con il parametro path per renderli ricercabili sia autonomamente che insieme, come segue:

curl -XPUT 'http://127.0.0.1:9200/test/?pretty=1' -d ' 
{ 
    "mappings" : { 
     "test" : { 
     "properties" : { 
      "firstname" : { 
       "fields" : { 
        "firstname" : { 
        "type" : "string" 
        }, 
        "any_name" : { 
        "type" : "string" 
        } 
       }, 
       "path" : "just_name", 
       "type" : "multi_field" 
      }, 
      "lastname" : { 
       "fields" : { 
        "any_name" : { 
        "type" : "string" 
        }, 
        "lastname" : { 
        "type" : "string" 
        } 
       }, 
       "path" : "just_name", 
       "type" : "multi_field" 
      } 
     } 
     } 
    } 
} 
' 

curl -XPOST 'http://127.0.0.1:9200/test/test?pretty=1' -d ' 
{ 
    "firstname" : "john", 
    "lastname" : "smith" 
} 
' 

Ricerca campo any_name funziona:

curl -XGET 'http://127.0.0.1:9200/test/test/_search?pretty=1' -d ' 
{ 
    "query" : { 
     "match" : { 
     "any_name" : { 
      "operator" : "and", 
      "query" : "john smith" 
     } 
     } 
    } 
} 
' 

# { 
# "hits" : { 
#  "hits" : [ 
#   { 
#    "_source" : { 
#    "firstname" : "john", 
#    "lastname" : "smith" 
#    }, 
#    "_score" : 0.2712221, 
#    "_index" : "test", 
#    "_id" : "Xf9qqKt0TpCuyLWioNh-iQ", 
#    "_type" : "test" 
#   } 
#  ], 
#  "max_score" : 0.2712221, 
#  "total" : 1 
# }, 
# "timed_out" : false, 
# "_shards" : { 
#  "failed" : 0, 
#  "successful" : 5, 
#  "total" : 5 
# }, 
# "took" : 11 
# } 

Ricerca firstname per john AND smith doesn' t work:

curl -XGET 'http://127.0.0.1:9200/test/test/_search?pretty=1' -d ' 
{ 
    "query" : { 
     "match" : { 
     "firstname" : { 
      "operator" : "and", 
      "query" : "john smith" 
     } 
     } 
    } 
} 
' 

# { 
# "hits" : { 
#  "hits" : [], 
#  "max_score" : null, 
#  "total" : 0 
# }, 
# "timed_out" : false, 
# "_shards" : { 
#  "failed" : 0, 
#  "successful" : 5, 
#  "total" : 5 
# }, 
# "took" : 2 
# } 

Ma la ricerca firstname solo john funziona correttamente:

curl -XGET 'http://127.0.0.1:9200/test/test/_search?pretty=1' -d ' 
{ 
    "query" : { 
     "match" : { 
     "firstname" : { 
      "operator" : "and", 
      "query" : "john" 
     } 
     } 
    } 
} 
' 

# { 
# "hits" : { 
#  "hits" : [ 
#   { 
#    "_source" : { 
#    "firstname" : "john", 
#    "lastname" : "smith" 
#    }, 
#    "_score" : 0.30685282, 
#    "_index" : "test", 
#    "_id" : "Xf9qqKt0TpCuyLWioNh-iQ", 
#    "_type" : "test" 
#   } 
#  ], 
#  "max_score" : 0.30685282, 
#  "total" : 1 
# }, 
# "timed_out" : false, 
# "_shards" : { 
#  "failed" : 0, 
#  "successful" : 5, 
#  "total" : 5 
# }, 
# "took" : 3 
# } 
0

penso "match" di query è quello che state cercando:.

"La partita famiglia di query non passa attraverso un‘processo di query di analisi’Non supporta nome di campo prefissi, jolly personaggi, o altre caratteristiche "avanzate" .Per questo motivo, le probabilità che si guasti sono molto piccole/inesistenti e forniscono un comportamento eccellente quando si tratta di analizzare ed eseguire quel testo come comportamento di una query (che di solito è ciò che casella di ricerca testo) "

http://www.elasticsearch.org/guide/reference/query-dsl/match-query.html