Usando Procura do IBM Cloudant
Os índices de pesquisa fornecem uma maneira de consultar um banco de dados usando a sintaxe do Lucene Query Parser. Um índice de procura usa um ou mais campos de seus documentos.
É possível usar um índice de procura para executar consultas, localizar documentos com base no conteúdo que eles incluem ou trabalhar com grupos, máscaras ou procuras geográficas.
Para criar um índice de procura, você inclui uma função JavaScript em um documento de design no banco de dados. Um índice é construído após ele processar uma solicitação de procura ou após o servidor detectar uma atualização de documento. A função
index
usa os parâmetros a seguir:
- Nome do campo - O nome do campo a ser usado ao consultar o índice. Se você configurar esse parâmetro como
default
, o campo será consultado se nenhum outro for especificado na sintaxe de consulta. - Dados que você deseja indexar, por exemplo,
doc.address.country
. - (Opcional) O terceiro parâmetro inclui os campos a seguir:
boost
,facet
,index
estore
. Esses campos são descritos com detalhes posteriormente.
Por padrão, uma resposta de índice de procura retorna 25 linhas. O número de linhas que são retornadas pode ser mudado usando o parâmetro limit
. No entanto, um conjunto de resultados de uma procura é limitado a 200 linhas. Cada resposta
inclui um campo bookmark
. É possível incluir o valor do campo bookmark
em consultas posteriores para consultar as respostas.
É possível consultar a API usando um dos métodos a seguir: URI, Painel do IBM Cloudant, curl ou um plug-in do navegador, como Postman ou RESTClient.
Veja o exemplo de documento de design a seguir que define um índice de procura:
{
"_id": "_design/search_example",
"indexes": {
"animals": {
"index": "function(doc){ ... }"
}
}
}
Tipo de particionamento de índice de procura
Um índice de pesquisa herda o tipo de particionamento do options.partitioned
do documento de design que o contém.
Funções de índice
Se você tentar indexar usando um campo de dados que não existe, a tentativa falhará. Para evitar esse problema, use uma cláusula guard apropriada.
Suas funções de indexação operam em um ambiente com restrição de memória no qual o próprio documento forma uma parte da memória usada nesse ambiente. A pilha e o documento do seu código devem caber dentro dessa memória. Os documentos são limitados a um tamanho máximo de 64 MB.
Dentro de um índice de procura, não indexe o mesmo nome de campo com mais de um tipo de dados. É possível que você receba um erro, caso o mesmo nome de campo seja indexado com tipos de dados diferentes na mesma função de índice de procura. Esse
erro ocorre quando você consulta o índice de pesquisa que diz o campo was indexed without position data
. Por exemplo, não inclua ambas as linhas na mesma função de índice de procura. Essas linhas indexam o campo myfield
como dois tipos de dados diferentes, uma sequência "this is a string"
e um número 123
.
index("myfield", "this is a string");
index("myfield", 123);
A função que está contida no campo de índice é uma função JavaScript que é chamada para cada documento no banco de dados. A função usa o documento como um parâmetro, extrai alguns dados dele e, em seguida, chama a função que é definida no campo
index
para indexar esses dados.
A função index
usa três parâmetros, sendo que o terceiro parâmetro é opcional.
O primeiro parâmetro é o nome do campo que você pretende usar ao consultar o índice, que é especificado na parte da sintaxe do Lucene de consultas posteriores. Um exemplo aparece na consulta a seguir:
query=color:red
O nome do campo do Lucene color
é o primeiro parâmetro da função index
.
O parâmetro query
pode ser abreviado para q
, portanto, outra maneira de gravar a consulta é mostrada no exemplo a seguir.
q=color:red
Se o valor especial "default"
for usado quando você definir o nome, você não precisará especificar um nome de campo no momento da consulta. O efeito é que a consulta pode ser simplificada:
query=red
O segundo parâmetro são os dados a serem indexados. Tenha as informações a seguir em mente ao indexar seus dados:
- Esses dados só devem ser do tipo sequência, número ou booleano. Outros tipos retornam um erro da chamada de função de índice.
- Se for retornado um erro quando sua função estiver em execução, por essa ou outra razão, o documento não será incluído nesse índice de procura.
O terceiro parâmetro, opcional, é um objeto JavaScript com os campos a seguir:
Opção | Descrição | Valores | Padrão |
---|---|---|---|
boost |
Um número que especifica a relevância em resultados de procura. O conteúdo que é indexado com um valor de impulso maior que 1 é mais relevante do que o conteúdo que é indexado sem um valor de impulso. O conteúdo com um valor de impulso menor que um não é tão relevante. | Um número de vírgula flutuante positivo | 1 (Sem impulso) |
facet |
Cria um índice de máscara. Para obter mais informações, consulte Mascaramento. | true |
false |
index |
Se os dados são indexados e, se sim, como. Se configurados como false , os dados não poderão ser usados para procuras, mas ainda poderão ser recuperados do índice se store for configurado como true .
Para obter mais informações, consulte Analisadores. |
true , false |
true |
store |
Se true , o valor será retornado no resultado da procura; caso contrário, o valor não será retornado. |
true , false |
false |
Se você não configurar o parâmetro store
, os resultados dos dados do índice para o documento não serão retornados na resposta para uma consulta.
Veja a função de índice de procura de exemplo a seguir:
function(doc) {
index("default", doc._id);
if (doc.min_length) {
index("min_length", doc.min_length, {"store": true});
}
if (doc.diet) {
index("diet", doc.diet, {"store": true});
}
if (doc.latin_name) {
index("latin_name", doc.latin_name, {"store": true});
}
if (doc.class) {
index("class", doc.class, {"store": true});
}
}
Armazenamento vs include_docs=true
Quando o IBM Cloudant retorna dados de uma procura, é possível escolher entre as opções a seguir: store: true
ou include_docs=true
. Veja as descrições a seguir:
- Em index-time, escolha a opção
{store: true}
. Essa opção indica que o campo com o qual você está lidando precisa ser armazenado dentro do índice. Um campo pode ser "armazenado" mesmo que ele não seja usado para indexação em si. Por exemplo, talvez você deseje "armazenar" um número de telefone, mesmo se o seu algoritmo de procura não incluir pesquisa por número de telefone. - No momento da consulta, passe
?include_docs=true
para indicar ao IBM Cloud que você deseja que o corpo inteiro de cada documento correspondente seja retornado.
A primeira opção significa que você tem um índice maior, mas é a maneira mais rápida de recuperar dados. A segunda opção mantém o índice pequeno, mas inclui trabalho extra de tempo de consulta para a IBM Cloud pois ela deve buscar corpos de documentos após o conjunto de resultados da procura ser calculado. Esse processo pode ser mais lento para ser executado e inclui uma carga adicional ao cluster da IBM Cloud.
Se possível, escolha a primeira opção usando as seguintes diretrizes:
- Indexar somente os campos que você deseja que sejam pesquisáveis.
- Armazenar somente os campos que você precisa recuperar no momento da consulta.
Cláusulas guard de índice
A função index
requer o nome do campo de dados para indexar como o segundo parâmetro. No entanto, se esse campo de dados não existir para o documento, ocorrerá um erro. A solução é usar uma "cláusula de proteção" apropriada
que verifique se o campo existe. Essa cláusula contém o tipo de dado esperado antes de qualquer tentativa de criar o índice correspondente.
Veja a definição de exemplo a seguir que não tem nenhuma validação no tipo de campo de dados do índice:
if (doc.min_length) {
index("min_length", doc.min_length, {"store": true});
}
É possível usar o operador do JavaScript typeof
para implementar o teste da cláusula guard. Se o campo existir e tiver o tipo esperado, o nome do tipo correto será retornado. O teste da cláusula guard será bem-sucedido, o que
significa que é seguro usar a função de índice. Se o campo não existir, você não obterá o tipo de campo esperado e, por isso, não tentará indexar o campo.
O JavaScript considera um resultado falso se um dos valores a seguir é testado:
- 'indefinido'
- Nulo
- O número +0
- O número -0
- NaN (não é um número)
- "" (sequência vazia)
Antes de realizar a indexação, veja o exemplo a seguir que usa uma cláusula guard para verificar se o campo de dados necessário existe e se ele contém um número:
if (typeof doc.min_length === 'number') {
index("min_length", doc.min_length, {"store": true});
}
Use um teste da cláusula guard genérica para assegurar que o tipo do campo de dados do candidato seja definido.
Veja o exemplo a seguir de uma cláusula guard "genérica":
if (typeof doc.min_length) !== 'undefined') {
// The field exists, and does have a type, so we can proceed to index using it.
...
}
Analisadores
Os analisadores são configurações que definem como reconhecer termos dentro do texto. Para obter mais informações, consulte Analisadores de pesquisa.
Os analisadores poderão ser úteis se for necessário indexar diversos idiomas.
A tabela a seguir mostra uma lista de analisadores genéricos que são compatíveis com a pesquisa IBM Cloudant:
Analisador | Descrição |
---|---|
classic |
O analisador padrão Lucene, circa versão 3.1. |
email |
Igual ao analisador standard , mas tenta corresponder a um endereço de e-mail como um token completo. |
keyword |
A entrada não é convertida em token. |
simple |
Divide o texto em não letras. |
simple_asciifolding |
Divide o texto em não letras. Converte caracteres para o equivalente ASCII mais próximo |
standard |
O analisador padrão. Ele implementa as regras de quebra de palavras do algoritmo de segmentação de texto Unicode™). |
whitespace |
Divide o texto nos limites do espaço em branco. |
Veja o exemplo de documento analisador a seguir:
{
"_id": "_design/analyzer_example",
"indexes": {
"INDEX_NAME": {
"index": "function (doc) { ... }",
"analyzer": "$ANALYZER_NAME"
}
}
}
Analisadores específicos do idioma
Esses analisadores omitem palavras comuns no idioma específico, e muitos também removem prefixos e sufixos. O nome do idioma também é o nome do analisador.
arabic
armenian
basque
bulgarian
brazilian
catalan
cjk
(chinês, japonês, coreano)chinese
(smartcn
)czech
danish
dutch
english
finnish
french
german
greek
galician
hindi
hungarian
indonesian
irish
italian
japanese
(kuromoji
)latvian
norwegian
persian
polish
(stempel
)portuguese
romanian
russian
spanish
swedish
thai
turkish
Os analisadores específicos do idioma são otimizados para o idioma especificado. Não é possível combinar um analisador genérico com um analisador específico do idioma. Em vez disso, você pode usar um analisador perfield
para selecionar diferentes analisadores para diferentes campos nos documentos.
Analisadores por campo
O analisador perfield
configura muitos analisadores para campos diferentes.
Veja o exemplo a seguir que define analisadores diferentes para campos diferentes:
{
"_id": "_design/analyzer_example",
"indexes": {
"INDEX_NAME": {
"analyzer": {
"name": "perfield",
"default": "english",
"fields": {
"spanish": "spanish",
"german": "german"
}
},
"index": "function (doc) { ... }"
}
}
}
Palavras vazias
Palavras vazias são aquelas que não são indexadas. Você as define dentro de um documento de design transformando a sequência do analisador em um objeto.
Os analisadores keyword
, simple
e whitespace
não suportam palavras vazias.
As palavras vazias padrão para o analisador standard
estão incluídas na lista a seguir:
"a", "an", "and", "are", "as", "at", "be", "but", "by", "for", "if",
"in", "into", "is", "it", "no", "not", "of", "on", "or", "such",
"that", "the", "their", "then", "there", "these", "they", "this",
"to", "was", "will", "with"
Veja o exemplo a seguir que define palavras não indexadas ("stop"):
{
"_id": "_design/stop_words_example",
"indexes": {
"INDEX_NAME": {
"analyzer": {
"name": "portuguese",
"stopwords": [
"foo",
"bar",
"baz"
]
},
"index": "function (doc) { ... }"
}
}
}
Testando a tokenização do analisador
É possível testar os resultados da tokenização do analisador ao postar dados de amostra para o terminal _search_analyze
.
Veja o exemplo a seguir que usa HTTP para testar o analisador keyword
:
Host: $ACCOUNT.cloudant.com
POST /_search_analyze HTTP/1.1
Content-Type: application/json
{"analyzer":"keyword", "text":"ablanks@renovations.com"}
Veja o exemplo a seguir que usa a linha de comandos para testar o analisador keyword
:
curl "https://$ACCOUNT.cloudant.com/_search_analyze" \
-H "Content-Type: application/json" \
-d '{"analyzer":"keyword", "text":"ablanks@renovations.com"}'
import com.ibm.cloud.cloudant.v1.Cloudant;
import com.ibm.cloud.cloudant.v1.model.PostSearchAnalyzeOptions;
import com.ibm.cloud.cloudant.v1.model.SearchAnalyzeResult;
Cloudant service = Cloudant.newInstance();
PostSearchAnalyzeOptions searchAnalyzerOptions =
new PostSearchAnalyzeOptions.Builder()
.analyzer("keyword")
.text("ablanks@renovations.com")
.build();
SearchAnalyzeResult response =
service.postSearchAnalyze(searchAnalyzerOptions).execute()
.getResult();
System.out.println(response);
import { CloudantV1 } from '@ibm-cloud/cloudant';
const service = CloudantV1.newInstance({});
service.postSearchAnalyze({
analyzer: 'keyword',
text: 'ablanks@renovations.com',
}).then(response => {
console.log(response.result);
});
from ibmcloudant.cloudant_v1 import CloudantV1
service = CloudantV1.new_instance()
response = service.post_search_analyze(
analyzer='keyword',
text='ablanks@renovations.com'
).get_result()
print(response)
postSearchAnalyzeOptions := service.NewPostSearchAnalyzeOptions(
"keyword",
"ablanks@renovations.com",
)
searchAnalyzeResult, _, err := service.PostSearchAnalyze(postSearchAnalyzeOptions)
if err != nil {
panic(err)
}
b, _ := json.MarshalIndent(searchAnalyzeResult, "", " ")
fmt.Println(string(b))
O exemplo do Go anterior requer o bloco de importação a seguir:
import (
"encoding/json"
"fmt"
"github.com/IBM/cloudant-go-sdk/cloudantv1"
)
Veja o resultado a seguir que testa o analisador keyword
:
{
"tokens": [
"ablanks@renovations.com"
]
}
Veja o exemplo a seguir que usa HTTP para testar o analisador standard
:
Host: $ACCOUNT.cloudant.com
POST /_search_analyze HTTP/1.1
Content-Type: application/json
{"analyzer":"standard", "text":"ablanks@renovations.com"}
Veja o exemplo a seguir que usa a linha de comandos para testar o analisador standard
:
curl "https://$ACCOUNT.cloudant.com/_search_analyze" -H "Content-Type: application/json"
-d '{"analyzer":"standard", "text":"ablanks@renovations.com"}'
Veja o resultado a seguir do teste do analisador standard
:
{
"tokens": [
"ablanks",
"renovations.com"
]
}
Consultas
Depois de criar um índice de procura, é possível consultá-lo.
-
Execute uma consulta de partição usando a solicitação a seguir:
GET /$DATABASE/_partition/$PARTITION_KEY/_design/$DDOC/_search/$INDEX_NAME
-
Execute uma consulta global usando a solicitação a seguir:
GET /$DATABASE/_design/$DDOC/_search/$INDEX_NAME
Especifique sua procura usando o parâmetro query
.
Veja o exemplo a seguir que usa HTTP para consultar um índice particionado:
GET /$DATABASE/_partition/$PARTITION_KEY/_design/$DDOC/_search/$INDEX_NAME?include_docs=true&query="*:*"&limit=1 HTTP/1.1
Content-Type: application/json
Host: $ACCOUNT.cloudant.com
Veja o exemplo a seguir que usa a linha de comandos para consultar um índice particionado:
curl "https://$ACCOUNT.cloudant.com/$DATABASE/_partition/$PARTITION_KEY/_design/$DDOC/_search/$INDEX_NAME?include_docs=true&query=\"*:*\"&limit=1"
import com.ibm.cloud.cloudant.v1.Cloudant;
import com.ibm.cloud.cloudant.v1.model.PostPartitionSearchOptions;
import com.ibm.cloud.cloudant.v1.model.SearchResult;
Cloudant service = Cloudant.newInstance();
PostPartitionSearchOptions searchOptions =
new PostPartitionSearchOptions.Builder()
.db("<db-name>")
.partitionKey("<partition-key>")
.ddoc("<ddoc>")
.index("<index-name>")
.query("*:*")
.includeDocs(true)
.limit(1)
.build();
SearchResult response =
service.postPartitionSearch(searchOptions).execute()
.getResult();
System.out.println(response);
import { CloudantV1 } from '@ibm-cloud/cloudant';
const service = CloudantV1.newInstance({});
service.postSearch({
db: '<db-name>',
partitionKey: '<partition-key>',
ddoc: '<ddoc>',
index: '<index-name>',
query: '*:*',
includeDocs: true,
limit: 1
}).then(response => {
console.log(response.result);
});
from ibmcloudant.cloudant_v1 import CloudantV1
service = CloudantV1.new_instance()
response = service.post_search(
db='<db-name>',
partition_key='<partition-key>',
ddoc='<ddoc>',
index='<index-name>',
query='*:*',
include_docs=True,
limit=1
).get_result()
print(response)
postPartitionSearchOptions := service.NewPostPartitionSearchOptions(
"<db-name>",
"<partition-key>",
"<ddoc>",
"<index-name>",
"*:*",
)
postPartitionSearchOptions.SetIncludeDocs(true)
postPartitionSearchOptions.SetLimit(1)
searchResult, _, err := service.PostPartitionSearch(postPartitionSearchOptions)
if err != nil {
panic(err)
}
b, _ := json.MarshalIndent(searchResult, "", " ")
fmt.Println(string(b))
O exemplo do Go anterior requer o bloco de importação a seguir:
import (
"encoding/json"
"fmt"
"github.com/IBM/cloudant-go-sdk/cloudantv1"
)
Veja o exemplo a seguir que usa HTTP para consultar um índice global:
GET /$DATABASE/_design/$DDOC/_search/$INDEX_NAME?include_docs=true&query="*:*"&limit=1 HTTP/1.1
Content-Type: application/json
Host: $ACCOUNT.cloudant.com
Veja o exemplo a seguir que usa a linha de comandos para consultar um índice global:
curl "https://$ACCOUNT.cloudant.com/$DATABASE/_design/$DDOC/_search/$INDEX_NAME?include_docs=true&query=\"*:*\"&limit=1"
import com.ibm.cloud.cloudant.v1.Cloudant;
import com.ibm.cloud.cloudant.v1.model.PostSearchOptions;
import com.ibm.cloud.cloudant.v1.model.SearchResult;
Cloudant service = Cloudant.newInstance();
PostSearchOptions searchOptions = new PostSearchOptions.Builder()
.db("<db-name>")
.ddoc("<ddoc>")
.index("<index-name>")
.query("*:*")
.includeDocs(true)
.limit(1)
.build();
SearchResult response =
service.postSearch(searchOptions).execute()
.getResult();
System.out.println(response);
import { CloudantV1 } from '@ibm-cloud/cloudant';
const service = CloudantV1.newInstance({});
service.postSearch({
db: '<db-name>',
ddoc: '<ddoc>',
index: '<index-name>',
query: '*:*',
includeDocs: true,
limit: 1
}).then(response => {
console.log(response.result);
});
from ibmcloudant.cloudant_v1 import CloudantV1
service = CloudantV1.new_instance()
response = service.post_search(
db='<db-name>',
ddoc='<ddoc>',
index='<index-name>',
query='*:*',
include_docs=True,
limit=1
).get_result()
print(response)
postSearchOptions := service.NewPostSearchOptions(
"<db-name>",
"<ddoc>",
"<index-name>",
"*:*",
)
postSearchOptions.SetIncludeDocs(true)
postSearchOptions.SetLimit(1)
searchResult, _, err := service.PostSearch(postSearchOptions)
if err != nil {
panic(err)
}
b, _ := json.MarshalIndent(searchResult, "", " ")
fmt.Println(string(b))
O exemplo do Go anterior requer o bloco de importação a seguir:
import (
"encoding/json"
"fmt"
"github.com/IBM/cloudant-go-sdk/cloudantv1"
)
Parâmetros de consulta
Deve-se ativar o mascaramento para usar os parâmetros a seguir: counts
e drilldown
.
Argumento | Descrição | Opcional | Tipo | Valores suportados | Consulta de partição |
---|---|---|---|---|---|
bookmark |
Um marcador que foi recebido de uma procura anterior. Esse parâmetro permite a paginação por meio dos resultados. Se não existir nenhum resultado após o marcador, você obterá uma resposta com uma matriz de linhas vazias e o mesmo marcador, confirmando o término da lista de resultados. | yes |
Sequência | Sim | |
counts |
Este campo define uma matriz de nomes de campos de sequência para os quais são solicitadas contagens. A resposta inclui contagens para cada valor exclusivo desse nome de campo entre os documentos que correspondem à consulta de procura. A máscara deve ser ativada para que esse parâmetro funcione. | Sim | JSON | Uma matriz JSON de nomes de campo. | Não |
drilldown |
Este campo pode ser usado várias vezes. Cada uso define um par de um nome de campo e um valor. A procura corresponde apenas a documentos que incluem o valor que foi fornecido no campo nomeado. Ela difere do uso de "fieldname:value" no parâmetro q apenas porque os valores não são analisados. A máscara deve ser ativada para que esse parâmetro funcione. |
Não | JSON | Uma matriz JSON que inclui dois elementos: o nome do campo e o valor. | Sim |
group_field |
Campo pelo qual agrupar as correspondências de procura. | Sim | Sequência | Uma sequência que inclui o nome de um campo de sequência. Campos que incluem outros dados, como números, objetos ou matrizes, não podem ser usados. | Não |
group_limit |
Contagem máxima de grupo. Este campo poderá ser usado apenas se group_field for especificado. |
Sim | Numéricos | Não | |
group_sort |
Este campo define a ordem dos grupos em uma procura que usa group_field . O padrão de ordenação é a relevância. |
Sim | JSON | Este campo pode ter os mesmos valores que o campo de classificação, portanto, campos únicos e matrizes de campos são suportados. | Não |
highlight_fields |
Especifica quais campos devem ser destacados. Se especificado, o objeto de resultado incluirá um campo highlights com uma entrada para cada campo especificado. |
Sim | Matriz de sequências | Sim | |
highlight_pre_tag |
Uma sequência que é inserida antes da palavra destacada na saída de destaques. | Sim, padroniza como <em> |
Sequência | Sim | |
highlight_post_tag |
Uma sequência que é inserida após a palavra destacada na saída de destaques. | Sim, padroniza como </em> |
Sequência | Sim | |
highlight_number |
Número de fragmentos que são retornados em destaques. Se o termo da procura exceder o tamanho do fragmento, o termo da procura inteiro será retornado. | Sim, padronizado para 1 | Numéricos | Sim | |
highlight_size |
Fatia o conteúdo do campo em número de caracteres, os chamados fragmentos, e destaca correspondências somente dentro dos fragmentos especificados. | Sim, padronizado para 100 caracteres | Numéricos | Sim | |
include_docs |
Inclua o conteúdo completo dos documentos na resposta. | Sim | Booleano | Sim | |
include_fields |
Uma matriz JSON de nomes de campo para incluir em resultados de procura. Quaisquer campos incluídos devem ser indexados com a opção store:true . |
Sim, o padrão é todos os campos. | Matriz de sequências | Sim | |
limit |
Limite o número dos documentos retornados ao número especificado. Para uma procura agrupada, esse parâmetro limita o número de documentos por grupo. | Sim | Numéricos | O valor limite pode ser qualquer número inteiro positivo até e incluindo 200. | Sim |
q |
Abreviação para query . Executa uma consulta Lucene. |
Não | Sequência ou Número | Sim | |
query |
Executa uma consulta Lucene. | Não | Sequência ou Número | Sim | |
ranges |
Este campo define intervalos para campos de procura numéricos utilizando máscara. O valor é um objeto JSON no qual os nomes de campos são campos de procura numéricos utilizando máscara e os valores dos campos são objetos JSON. Os nomes
de campo dos objetos JSON são nomes para intervalos. Os valores são sequências que descrevem o intervalo, por exemplo, "[0 TO 10]" . |
Sim | JSON | O valor deve ser um objeto com campos que tenham objetos como seus valores. Esses objetos devem ter sequências com intervalos conforme seus valores de campo. | Não |
sort |
Especifica a ordem de classificação dos resultados. Em uma procura agrupada (quando group_field é usado), esse parâmetro especifica a ordem de classificação dentro de um grupo. O padrão de ordenação é a relevância. |
Sim | JSON | Uma sequência JSON do formulário "fieldname<type>" ou -fieldname<type> para ordem decrescente. O fieldname é o nome de um campo de Sequência ou Número e type é
um número, uma sequência ou uma matriz JSON de sequências. A parte type é opcional e é padronizada para number . Alguns exemplos são "foo" , "-foo" , "bar<string>" ,
"-foo<number>" e ["-foo<number>","bar<string>"] . Os campos de sequência que são usados para classificação não devem ser campos analisados. Os campos que são
usados para classificação devem ser indexados pelo mesmo indexador que é usado para a consulta de procura. |
Sim |
stale |
Não espere que o índice termine a construção para retornar resultados. | Sim | Sequência | OK | Sim |
Não combine as opções bookmark
e stale
. Essas opções restringem a opção de réplicas de shard ao uso para a resposta. Quando usadas juntas, as opções podem causar problemas quando você tenta contatar réplicas que estão
lentas ou não estão disponíveis.
O uso de include_docs=true
pode resultar em implicações de desempenho.
Relevância
Quando mais de um resultado puder ser retornado, será possível classificá-los. Por padrão, a ordem de classificação é determinada por 'relevância'.
A relevância é medida de acordo com Apache Pontuação Lucene. Por exemplo, ao procurar a palavra example
em um banco de dados simples,
dois documentos podem contê-la. Se um documento mencionar a palavra example
10 vezes e outro mencioná-la apenas duas vezes, o primeiro será considerado mais 'relevante'.
Se você não fornecer um parâmetro sort
, a relevância será usada por padrão. As correspondências de pontuação mais altas são retornadas primeiro.
Se você fornecer um parâmetro sort
, as correspondências serão retornadas nessa ordem, ignorando a relevância.
Se você deseja usar um parâmetro sort
e também incluir ordenação por relevância em seus resultados de procura, use os campos especiais -<score>
ou <score>
dentro do parâmetro sort
.
Consultas de procura de POSTing
Em vez de usar o método HTTP GET
, também é possível usar POST
. A principal vantagem das consultas do POST
é que elas podem ter um corpo de solicitação, portanto, é possível especificar a solicitação como
um objeto JSON. Cada parâmetro na tabela anterior corresponde a um campo no objeto JSON no corpo da solicitação.
Veja o exemplo a seguir que usa HTTP para POST
de uma solicitação de procura:
POST /db/_design/ddoc/_search/searchname HTTP/1.1
Content-Type: application/json
Host: $ACCOUNT.cloudant.com
Veja o exemplo a seguir que usa a linha de comandos para POST
de uma solicitação de procura:
curl "https://$ACCOUNT.cloudant.com/$DATABASE/_design/$DDOC/_search/$INDEX_NAME" -X POST -H "Content-Type: application/json" -d @search.json
Veja o documento JSON de exemplo a seguir que inclui uma solicitação de procura:
{
"q": "index:my query",
"sort": "foo",
"limit": 3
}
Sintaxe da Consulta
A sintaxe de consulta de pesquisa do IBM Cloudant é baseada na sintaxe do Sintaxe do Lucene.
As consultas de procura assumem a forma de name:value
, a menos que o nome seja omitido, em cujo caso elas usam o campo padrão, conforme demonstrado nos exemplos a seguir:
Veja as expressões de consulta de procura de exemplo a seguir:
// Birds
class:bird
// Animals that begin with the letter "l"
l*
// Carnivorous birds
class:bird AND diet:carnivore
// Herbivores that start with letter "l"
l* AND diet:herbivore
// Medium-sized herbivores
min_length:[1 TO 3] AND diet:herbivore
// Herbivores that are 2m long or less
diet:herbivore AND min_length:[-Infinity TO 2]
// Mammals that are at least 1.5m long
class:mammal AND min_length:[1.5 TO Infinity]
// Find "Meles meles"
latin_name:"Meles meles"
// Mammals who are herbivore or carnivore
diet:(herbivore OR omnivore) AND class:mammal
// Return all results
*:*
As consultas em vários campos podem ser combinadas logicamente e grupos e campos podem ser agrupados ainda mais. Os operadores lógicos disponíveis diferenciam maiúsculas de minúsculas e são AND
,
+
,
OR
,
NOT
, and -
. As consultas de intervalo podem ser executadas em sequências ou números.
Para realizar uma procura difusa, execute uma consulta com ~
a fim de localizar termos como o termo de procura. Por exemplo,
look~
encontra os termos book
e took
.
Se os limites mais altos de uma consulta de intervalo forem sequências que contêm apenas dígitos numéricos, os limites serão tratados como números, e não como sequências. Por exemplo, se você procurar usando a consulta mod_date:["20170101" TO "20171231"]
,
os resultados incluirão documentos para os quais mod_date
esteja entre os valores numéricos 20170101 e 20171231, não entre as sequências "20170101" e "20171231".
É possível alterar a importância de um termo de procura incluindo ^
e um número positivo. Essa alteração cria correspondências que contêm o termo mais ou menos relevante, proporcional à potência do valor de impulso. O valor padrão
é 1, o que significa sem aumento ou diminuição na força da correspondência. Um valor decimal de 0 - 1 reduz a importância, tornando a força de correspondência mais fraca. Um valor maior que um aumenta a importância, tornando a força de correspondência
mais forte.
As pesquisas de curinga são suportadas para buscas de caractere único (?
) e múltiplo (*
). Por exemplo,
dat?
would match date
and data
, and dat*
would match date
,
data
,
database
, and dates
. Os curingas devem vir após o termo de procura.
Use *:*
para retornar todos os resultados.
Os conjuntos de resultados das procuras são limitados a 200 linhas e retornam 25 linhas por padrão. O número de linhas retornadas pode ser alterado usando o parâmetro limit
.
Se a consulta de procura não especificar o argumento "group_field"
, a resposta incluirá um marcador. Se esse marcador for fornecido posteriormente como um parâmetro de URL, a resposta irá ignorar as linhas já vistas, acelerando
e facilitando a obtenção do próximo conjunto de resultados.
A resposta nunca inclui um marcador se o parâmetro "group_field"
for incluído na consulta de pesquisa.
As opções group_field
, group_limit
e group_sort
estarão disponíveis somente quando você fizer consultas globais.
Os caracteres a seguir requerem escape para a procura neles:
+ - && || ! ( ) { } [ ] ^ " ~ * ? : \ /
Para escapar um desses caracteres, use um caractere de barra invertida anterior (\
).
A resposta para uma consulta de procura inclui um campo order
para cada um dos resultados. O campo order
é uma matriz na qual o primeiro elemento é o campo ou os campos especificados no parâmetro sort
.
Se nenhum parâmetro sort
for incluído na consulta, o campo order
conterá a pontuação de relevância do Lucene.
Se você usar o recurso sort by distance
conforme descrito em Procuras geográficas, o primeiro elemento será a distância de um ponto. A distância é medida usando quilômetros ou milhas.
O segundo elemento na matriz de ordem pode ser ignorado. Ele é usado somente para propósitos de resolução de problemas.
Mascaramento
O IBM Cloudant Search também suporta a procura utilizando máscara, o que permite a descoberta de informações agregadas sobre correspondências de forma rápida e fácil. É possível fazer a correspondência de todos os documentos usando a sintaxe
de consulta especial ?q=*:*
e usar as máscaras retornadas para refinar sua consulta. Para indicar que um campo deve ser indexado para consultas utilizando máscara, configure {"facet": true}
em suas opções.
Veja o exemplo de consulta de procura a seguir, especificando que a procura utilizando máscara está ativada:
function(doc) {
index("type", doc.type, {"facet": true});
index("price", doc.price, {"facet": true});
}
Para usar máscaras, todos os documentos no índice devem incluir todos os campos que têm mascaramento ativado. Se os seus documentos não incluírem todos os campos, você receberá um erro bad_request
com a razão a seguir: "O field_name
não existe." Se algum dos documentos não contiver todos os campos para máscaras, crie índices separados para cada campo. Ao não criar índices separados para cada campo, deve-se incluir apenas documentos que contenham todos os campos.
Verifique se os campos existem em cada documento usando uma única instrução if
.
Veja o exemplo de instrução if
a seguir para verificar se os campos necessários existem em cada documento:
if (typeof doc.town == "string" && typeof doc.name == "string") {
index("town", doc.town, {facet: true});
index("name", doc.name, {facet: true});
}
Counts
A opção counts
está disponível apenas quando você faz consultas globais.
A sintaxe de máscara counts
usa uma lista de campos e retorna o número de resultados de consulta para cada valor exclusivo de cada campo nomeado.
A operação count
funcionará apenas se os valores indexados forem sequências. Os valores indexados não podem ser tipos mistos. Por exemplo, se 100 sequências e um número forem indexados, o índice não poderá ser usado para operações
count
. Você pode verificar o tipo usando o operador typeof
, e convertê-lo usando o operador parseInt
,
parseFloat
, or .toString()
functions.
Veja a consulta de exemplo a seguir que usa a sintaxe de máscara counts
:
?q=*:*&counts=["type"]
Veja a resposta de exemplo a seguir depois de usar a sintaxe de máscara counts
:
{
"total_rows":100000,
"bookmark":"g...",
"rows":[...],
"counts":{
"type":{
"sofa": 10,
"chair": 100,
"lamp": 97
}
}
}
drilldown
A opção drilldown
está disponível apenas quando você faz consultas globais.
É possível restringir resultados a documentos com uma dimensão igual ao rótulo especificado. Restrinja os resultados incluindo drilldown=["dimension","label"]
em uma consulta de procura. É possível incluir
vários parâmetros drilldown
para restringir resultados ao longo de várias dimensões.
O uso de um parâmetro drilldown
é semelhante ao uso de key:value
no parâmetro q
, mas o parâmetro drilldown
retorna valores que o analisador pode ignorar.
Por exemplo, se o analisador não tiver indexado uma palavra vazia como "a"
, o parâmetro drilldown
a retornará quando você especificar drilldown=["key","a"]
.
Ranges
A opção ranges
está disponível apenas quando você faz consultas globais.
A sintaxe de máscara range
reutiliza a sintaxe padrão Lucene para intervalos para retornar contagens de resultados que se encaixam em cada categoria especificada. As consultas de intervalo inclusivo são indicadas por colchetes
([
, ]
). As consultas de intervalo exclusivo são indicadas por chaves ({
, }
).
Os valores indexados não podem ser tipos mistos. Por exemplo, se 100 sequências e um número forem indexados, o índice não poderá ser usado para operações range
. Você pode verificar o tipo usando o operador typeof
,
e convertê-lo usando o operador parseInt
,
parseFloat
, or .toString()
functions.
Veja o exemplo a seguir de uma solicitação que usa a procura utilizando máscara para correspondência de ranges
:
?q=*:*&ranges={"price":{"cheap":"[0 TO 100]","expensive":"{100 TO Infinity}"}}
Veja os resultados de exemplo a seguir após uma verificação de ranges
em uma procura utilizando máscara:
{
"total_rows":100000,
"bookmark":"g...",
"rows":[...],
"ranges": {
"price": {
"expensive": 278682,
"cheap": 257023
}
}
}
Procuras geográficas
Além de procurar por conteúdo de campos textuais, também é possível classificar seus resultados pela distância que eles estão de uma coordenada geográfica.
Para classificar os resultados dessa forma, deve-se indexar dois campos numéricos que representem a longitude e a latitude.
Em seguida, é possível consultar usando o campo de classificação especial <distance...>
, que leva cinco parâmetros:
- Nome do campo de longitude - O nome de seu campo de longitude (
mylon
no exemplo). - Nome do campo de latitude - O nome do seu campo de latitude (
mylat
no exemplo). - Origem da longitude - A longitude do lugar do qual você deseja classificar a distância.
- Origem da latitude - A latitude do lugar do qual você deseja classificar a distância.
- Unidades - As unidades a serem usadas incluem
km
para quilômetros oumi
para milhas. A distância é retornada no campo de ordem.
Você pode combinar a classificação por distância com qualquer outra consulta de pesquisa, como pesquisas de intervalo na latitude e longitude, ou consultas que envolvam informações não geográficas.
Dessa forma, é possível procurar em uma caixa delimitadora e limitar a procura com critérios adicionais.
Veja o exemplo de dados geográficos a seguir:
{
"name":"Aberdeen, Scotland",
"lat":57.15,
"lon":-2.15,
"type":"city"
}
Veja o exemplo a seguir de um documento de design que inclui um índice de procura para os dados geográficos:
function(doc) {
if (doc.type && doc.type == 'city') {
index('city', doc.name, {'store': true});
index('lat', doc.lat, {'store': true});
index('lon', doc.lon, {'store': true});
}
}
Veja o exemplo a seguir que usa HTTP para uma consulta que classifica cidades no hemisfério norte por sua distância de Nova Iorque:
GET /examples/_design/cities-designdoc/_search/cities?q=lat:[0+TO+90]&sort="<distance,lon,lat,-74.0059,40.7127,km>" HTTP/1.1
Host: $ACCOUNT.cloudant.com
Veja o exemplo a seguir que usa a linha de comandos para uma consulta que classifica cidades no hemisfério norte por sua distância de Nova Iorque:
curl "https://$ACCOUNT.cloudant.com/examples/_design/cities-designdoc/_search/cities?q=lat:\[0+TO+90\]&sort=\"<distance,lon,lat,-74.0059,40.7127,km>\""
import com.ibm.cloud.cloudant.v1.Cloudant;
import com.ibm.cloud.cloudant.v1.model.PostSearchOptions;
import com.ibm.cloud.cloudant.v1.model.SearchResult;
import java.util.Arrays;
Cloudant service = Cloudant.newInstance();
PostSearchOptions searchOptions = new PostSearchOptions.Builder()
.db("examples")
.ddoc("cities-designdoc")
.index("cities")
.query("lat:\\[0+TO+90\\]")
.sort(Arrays.asList("<distance,lon,lat,-74.0059,40.7127,km>"))
.build();
SearchResult response =
service.postSearch(searchOptions).execute()
.getResult();
System.out.println(response);
import { CloudantV1 } from '@ibm-cloud/cloudant';
const service = CloudantV1.newInstance({});
service.postSearch({
db: 'examples',
ddoc: 'cities-designdoc',
index: 'cities',
query: 'lat:\\[0+TO+90\\]',
sort: ['<distance,lon,lat,-74.0059,40.7127,km>']
}).then(response => {
console.log(response.result);
});
from ibmcloudant.cloudant_v1 import CloudantV1
service = CloudantV1.new_instance()
response = service.post_search(
db='examples',
ddoc='cities-designdoc',
index='cities',
query='lat:\\[0+TO+90\\]',
sort=['<distance,lon,lat,-74.0059,40.7127,km>']
).get_result()
print(response)
postSearchOptions := service.NewPostSearchOptions(
"examples",
"cities-designdoc",
"cities",
"lat:\\[0+TO+90\\]",
)
postSearchOptions.SetSort([]string{"<distance,lon,lat,-74.0059,40.7127,km>"})
searchResult, _, err := service.PostSearch(postSearchOptions)
if err != nil {
panic(err)
}
b, _ := json.MarshalIndent(searchResult, "", " ")
fmt.Println(string(b))
O exemplo do Go anterior requer o bloco de importação a seguir:
import (
"encoding/json"
"fmt"
"github.com/IBM/cloudant-go-sdk/cloudantv1"
)
Veja a resposta de exemplo a seguir (abreviada) que inclui uma lista de cidades do hemisfério norte que são classificadas pela distância de Nova Iorque:
{
"total_rows": 205,
"bookmark": "g1A...XIU",
"rows": [
{
"id": "city180",
"order": [
8.530665755719783,
18
],
"fields": {
"city": "New York, N.Y.",
"lat": 40.78333333333333,
"lon": -73.96666666666667
}
},
{
"id": "city177",
"order": [
13.756343205985946,
17
],
"fields": {
"city": "Newark, N.J.",
"lat": 40.733333333333334,
"lon": -74.16666666666667
}
},
{
"id": "city178",
"order": [
113.53603438866077,
26
],
"fields": {
"city": "New Haven, Conn.",
"lat": 41.31666666666667,
"lon": -72.91666666666667
}
}
]
}
Destacando termos de procura
Às vezes, é útil obter o contexto no qual um termo de procura foi mencionado para mostrar resultados mais enfatizados a um usuário.
Para obter resultados mais enfatizados, inclua o parâmetro highlight_fields
na consulta de procura. Especifique os nomes de campo para os quais você gostaria que trechos com o termo de procura destacado fossem retornados.
Por padrão, o termo de procura é colocado em tags <em>
para destacá-lo, mas o destaque pode ser substituído usando os parâmetros highlights_pre_tag
e highlights_post_tag
.
O comprimento dos fragmentos é de 100 caracteres por padrão. Um comprimento diferente pode ser solicitado com o parâmetro highlights_size
.
O parâmetro highlights_number
controla o número de fragmentos que são retornados e é padronizado para 1.
Na resposta, um campo highlights
é incluído com um subcampo por nome de campo.
Para cada campo, você recebe uma matriz de fragmentos com o termo de procura destacado.
Para o destaque funcionar, armazene o campo no índice usando a opção store: true
.
Veja o exemplo a seguir que usa HTTP para procurar com o destaque ativado:
GET /movies/_design/searches/_search/movies?q=movie_name:Azazel&highlight_fields=["movie_name"]&highlight_pre_tag=" "&highlight_post_tag=" "&highlights_size=30&highlights_number=2 HTTP/1.1
HOST: $ACCOUNT.cloudant.com
Authorization: ...
Veja no exemplo a seguir a linha de comando para pesquisar com o destaque ativado:
curl "https://$ACCOUNT.cloudant.com/movies/_design/searches/_search/movies?q=\"movie_name:Azazel\"&highlight_fields=\[\"movie_name\"\]&highlight_pre_tag=\" \"&highlight_post_tag=\" \"&highlights_size=30&highlights_number=2" \
-X GET
import com.ibm.cloud.cloudant.v1.Cloudant;
import com.ibm.cloud.cloudant.v1.model.PostSearchOptions;
import com.ibm.cloud.cloudant.v1.model.SearchResult;
import java.util.Arrays;
Cloudant service = Cloudant.newInstance();
PostSearchOptions searchOptions = new PostSearchOptions.Builder()
.db("movies")
.ddoc("searches")
.index("movies")
.query("movie_name:Azazel")
.highlightFields(Arrays.asList("[\"movie_name\"]"))
.highlightPreTag("\" \"")
.highlightPostTag("\" \"")
.highlightSize(30)
.highlightNumber(2)
.build();
SearchResult response =
service.postSearch(searchOptions).execute()
.getResult();
System.out.println(response);
import { CloudantV1 } from '@ibm-cloud/cloudant';
const service = CloudantV1.newInstance({});
service.postSearch({
db: 'movies',
ddoc: 'searches',
index: 'movies',
query: 'movie_name:Azazel',
highlightFields: ['["movie_name"]'],
highlightPreTag: '" "',
highlightPostTag: '" "',
highlightSize: 30,
highlightNumber: 2
}).then(response => {
console.log(response.result);
});
from ibmcloudant.cloudant_v1 import CloudantV1
service = CloudantV1.new_instance()
response = service.post_search(
db='movies',
ddoc='searches',
index='movies',
query='movie_name:Azazel',
highlight_fields=['["movie_name"]'],
highlight_pre_tag='" "',
highlight_post_tag='" "',
highlight_size=30,
highlight_number=2
).get_result()
print(response)
postSearchOptions := service.NewPostSearchOptions(
"movies",
"searches",
"movies",
"movie_name:Azazel",
)
postSearchOptions.SetHighlightFields([]string{"[\"movie_name\"]"})
postSearchOptions.SetHighlightPreTag("\" \"")
postSearchOptions.SetHighlightPostTag("\" \"")
postSearchOptions.SetHighlightSize(30)
postSearchOptions.SetHighlightNumber(2)
searchResult, _, err := service.PostSearch(postSearchOptions)
if err != nil {
panic(err)
}
b, _ := json.MarshalIndent(searchResult, "", " ")
fmt.Println(string(b))
O exemplo do Go anterior requer o bloco de importação a seguir:
import (
"encoding/json"
"fmt"
"github.com/IBM/cloudant-go-sdk/cloudantv1"
)
Veja o exemplo a seguir de resultados de procura destacados:
{
"highlights": {
"movie_name": [
" on the Azazel Orient Express",
" Azazel manuals, you"
]
}
}
Metadados do índice de procura
Para recuperar informações sobre um índice de procura, você envia uma solicitação GET
para o terminal _search_info
, conforme mostrado no exemplo a seguir.
DDOC
refere-se ao documento de design que inclui o índice e INDEX_NAME
é o nome do índice.
Veja o exemplo a seguir que usa HTTP para solicitar metadados de índice de procura:
GET /$DATABASE/_design/$DDOC/_search_info/$INDEX_NAME HTTP/1.1
Veja o exemplo a seguir que usa a linha de comandos para solicitar metadados de índice de procura:
curl "https://$ACCOUNT.cloudant.com/$DATABASE/_design/$DDOC/_search_info/$INDEX_NAME" \
-X GET
import com.ibm.cloud.cloudant.v1.Cloudant;
import com.ibm.cloud.cloudant.v1.model.GetSearchInfoOptions;
import com.ibm.cloud.cloudant.v1.model.SearchInfoResult;
Cloudant service = Cloudant.newInstance();
GetSearchInfoOptions infoOptions =
new GetSearchInfoOptions.Builder()
.db("<db-name>")
.ddoc("<ddoc>")
.index("<index-name>")
.build();
SearchInfoResult response =
service.getSearchInfo(infoOptions).execute()
.getResult();
System.out.println(response);
import { CloudantV1 } from '@ibm-cloud/cloudant';
const service = CloudantV1.newInstance({});
service.getSearchInfo({
db: '<db-name>',
ddoc: '<ddoc>',
index: '<index-name>'
}).then(response => {
console.log(response.result);
});
from ibmcloudant.cloudant_v1 import CloudantV1
service = CloudantV1.new_instance()
response = service.get_search_info(
db='<db-name>',
ddoc='<ddoc>',
index='<index-name>'
).get_result()
print(response)
getSearchInfoOptions := service.NewGetSearchInfoOptions(
"<db-name>",
"<ddoc>",
"<index-name>",
)
searchInfoResult, _, err := service.GetSearchInfo(getSearchInfoOptions)
if err != nil {
panic(err)
}
b, _ := json.MarshalIndent(searchInfoResult, "", " ")
fmt.Println(string(b))
O exemplo do Go anterior requer o bloco de importação a seguir:
import (
"encoding/json"
"fmt"
"github.com/IBM/cloudant-go-sdk/cloudantv1"
)
A resposta inclui informações sobre o seu índice, como o número de documentos no índice e o tamanho do índice no disco.
Veja a resposta de exemplo a seguir depois de solicitar metadados do índice de procura:
{
"name": "_design/DDOC/INDEX",
"search_index": {
"pending_seq": 7125496,
"doc_del_count": 129180,
"doc_count": 1066173,
"disk_size": 728305827,
"committed_seq": 7125496
}
}