Estou usando a elasticsearch para indexar meus documentos.
É possível instruí-lo a retornar apenas campos específicos em vez de todo o documento json armazenado?
Estou usando a elasticsearch para indexar meus documentos.
É possível instruí-lo a retornar apenas campos específicos em vez de todo o documento json armazenado?
Respostas:
Sim! Use um filtro de origem . Se você estiver pesquisando com JSON, será algo parecido com isto:
{
"_source": ["user", "message", ...],
"query": ...,
"size": ...
}
No ES 2.4 e versões anteriores, você também pode usar a opção de campos na API de pesquisa :
{
"fields": ["user", "message", ...],
"query": ...,
"size": ...
}
Isso foi preterido no ES 5+. E os filtros de origem são mais poderosos de qualquer maneira!
Achei os documentos get api
úteis - especialmente as duas seções, Filtragem de origem e Campos : https://www.elastic.co/guide/en/elasticsearch/reference/7.3/docs-get.html#get-source- filtragem
Eles afirmam sobre a filtragem de origem:
Se você precisar apenas de um ou dois campos do _source completo, poderá usar os parâmetros _source_include & _source_exclude para incluir ou filtrar as peças necessárias. Isso pode ser especialmente útil em documentos grandes, nos quais a recuperação parcial pode economizar na sobrecarga da rede
O que encaixava perfeitamente no meu caso de uso. Acabei filtrando a fonte assim (usando a abreviação):
{
"_source": ["field_x", ..., "field_y"],
"query": {
...
}
}
Para sua informação, eles informam nos documentos sobre o parâmetro fields :
A operação get permite especificar um conjunto de campos armazenados que serão retornados passando o parâmetro fields.
Parece atender a campos que foram especificamente armazenados, onde coloca cada campo em uma matriz. Se os campos especificados não tiverem sido armazenados, eles buscarão cada um dos _source, o que pode resultar em recuperações 'mais lentas'. Também tive problemas ao tentar fazê-lo retornar campos do tipo objeto.
Portanto, em resumo, você tem duas opções, seja através de filtros de origem ou campos [armazenados].
For the ES versions 5.X and above you can a ES query something like this
GET /.../...
{
"_source": {
"includes": [ "FIELD1", "FIELD2", "FIELD3" ... " ]
},
.
.
.
.
}
No Elasticsearch 5.x, a abordagem acima mencionada foi descontinuada. Você pode usar a abordagem _source, mas, em certas situações, pode fazer sentido armazenar um campo. Por exemplo, se você possui um documento com um título, uma data e um campo de conteúdo muito grande, convém recuperar apenas o título e a data sem precisar extrair esses campos de um campo _source grande:
Nesse caso, você usaria:
{
"size": $INT_NUM_OF_DOCS_TO_RETURN,
"stored_fields":[
"doc.headline",
"doc.text",
"doc.timestamp_utc"
],
"query":{
"bool":{
"must":{
"term":{
"doc.topic":"news_on_things"
}
},
"filter":{
"range":{
"doc.timestamp_utc":{
"gte":1451606400000,
"lt":1483228800000,
"format":"epoch_millis"
}
}
}
}
},
"aggs":{
}
}
Consulte a documentação sobre como indexar campos armazenados. Sempre feliz por um Upvote!
Todas as APIs REST aceitam um parâmetro filter_path que pode ser usado para reduzir a resposta retornada pelo elasticsearch. Este parâmetro utiliza uma lista de filtros separados por vírgula, expressa com a notação de ponto.
Aqui está outra solução, agora usando uma expressão de correspondência
Filtragem de origem
Permite controlar como o campo _source é retornado a cada ocorrência.
Testado com Elastiscsearch versão 5.5
A palavra-chave "inclui" define os campos específicos.
GET /my_indice/my_indice_type/_search
{
"_source": {
"includes": [ "my_especific_field"]
},
"query": {
"bool": {
"must": [
{"match": {
"_id": "%my_id_here_without_percent%"
}
}
]
}
}
}
Uma solicitação GET API REST pode ser feita com o parâmetro '_source'.
Solicitação de exemplo
http://localhost:9200/opt_pr/_search?q=SYMBOL:ITC AND OPTION_TYPE=CE AND TRADE_DATE=2017-02-10 AND EXPIRY_DATE=2017-02-23&_source=STRIKE_PRICE
Resposta
{
"took": 59,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 104,
"max_score": 7.3908954,
"hits": [
{
"_index": "opt_pr",
"_type": "opt_pr_r",
"_id": "AV3K4QTgNHl15Mv30uLc",
"_score": 7.3908954,
"_source": {
"STRIKE_PRICE": 160
}
},
{
"_index": "opt_pr",
"_type": "opt_pr_r",
"_id": "AV3K4QTgNHl15Mv30uLh",
"_score": 7.3908954,
"_source": {
"STRIKE_PRICE": 185
}
},
{
"_index": "opt_pr",
"_type": "opt_pr_r",
"_id": "AV3K4QTgNHl15Mv30uLi",
"_score": 7.3908954,
"_source": {
"STRIKE_PRICE": 190
}
},
{
"_index": "opt_pr",
"_type": "opt_pr_r",
"_id": "AV3K4QTgNHl15Mv30uLm",
"_score": 7.3908954,
"_source": {
"STRIKE_PRICE": 210
}
},
{
"_index": "opt_pr",
"_type": "opt_pr_r",
"_id": "AV3K4QTgNHl15Mv30uLp",
"_score": 7.3908954,
"_source": {
"STRIKE_PRICE": 225
}
},
{
"_index": "opt_pr",
"_type": "opt_pr_r",
"_id": "AV3K4QTgNHl15Mv30uLr",
"_score": 7.3908954,
"_source": {
"STRIKE_PRICE": 235
}
},
{
"_index": "opt_pr",
"_type": "opt_pr_r",
"_id": "AV3K4QTgNHl15Mv30uLw",
"_score": 7.3908954,
"_source": {
"STRIKE_PRICE": 260
}
},
{
"_index": "opt_pr",
"_type": "opt_pr_r",
"_id": "AV3K4QTgNHl15Mv30uL5",
"_score": 7.3908954,
"_source": {
"STRIKE_PRICE": 305
}
},
{
"_index": "opt_pr",
"_type": "opt_pr_r",
"_id": "AV3K4QTgNHl15Mv30uLd",
"_score": 7.381078,
"_source": {
"STRIKE_PRICE": 165
}
},
{
"_index": "opt_pr",
"_type": "opt_pr_r",
"_id": "AV3K4QTgNHl15Mv30uLy",
"_score": 7.381078,
"_source": {
"STRIKE_PRICE": 270
}
}
]
}
}
Sim, usando o filtro de origem, você pode fazer isso, aqui está o filtro de origem do documento
Solicitação de exemplo
POST index_name/_search
{
"_source":["field1","filed2".....]
}
A saída será
{
"took": 57,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 1,
"hits": [
{
"_index": "index_name",
"_type": "index1",
"_id": "1",
"_score": 1,
"_source": {
"field1": "a",
"field2": "b"
},
{
"field1": "c",
"field2": "d"
},....
}
]
}
}
Em java, você pode usar o setFetchSource assim:
client.prepareSearch(index).setTypes(type)
.setFetchSource(new String[] { "field1", "field2" }, null)
Por exemplo, você tem um documento com três campos:
PUT movie/_doc/1
{
"name":"The Lion King",
"language":"English",
"score":"9.3"
}
Se você deseja retornar name
e score
pode usar o seguinte comando:
GET movie/_doc/1?_source_includes=name,score
Se você deseja obter alguns campos que correspondem a um padrão:
GET movie/_doc/1?_source_includes=*re
Talvez exclua alguns campos:
GET movie/_doc/1?_source_excludes=score
Usando a API Java, uso o seguinte para obter todos os registros de um conjunto de campos específicos:
public List<Map<String, Object>> getAllDocs(String indexName) throws IOException{
int scrollSize = 1000;
List<Map<String,Object>> data = new ArrayList<>();
SearchResponse response = null;
while( response == null || response.getHits().getHits().length != 0){
response = client.prepareSearch(indexName)
.setTypes("typeName") // The document types to execute the search against. Defaults to be executed against all types.
.setQuery(QueryBuilders.matchAllQuery())
.setFetchSource(new String[]{"field1", "field2"}, null)
.setSize(scrollSize)
.execute()
.actionGet();
for(SearchHit hit : response.getHits()){
System.out.println(hit.getSourceAsString());
}
}
return data;
}