Fazer a elasticsearch retornar apenas determinados campos?

434

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?

user1199438
fonte
1
elastic.co/guide/en/elasticsearch/reference/current/... , nota thay você também pode excluir apenas alguns campos
Christophe Roussy

Respostas:

620

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!

kevingessner
fonte
12
defina-os como "armazenados": true no mapeamento. Caso contrário, o ES ainda carregará o documento _source e carregará os campos a partir daí. Pode afetar o desempenho se os dados retornados forem relativamente pequenos para o tamanho de um documento inteiro.
Zaar Hai
6
você quis dizer "loja": true
sscarduzio 17/02
são feitas no arquivo conf ou onde exatamente?
vbNewbie
@vbNewbie: Onde quer que você esteja definindo o mapeamento. Se você não estiver definindo o mapeamento explicitamente e confiando no ES para gerá-lo, precisará definir o mapeamento para os campos que deseja que o ES armazene. Você pode definir o mapeamento apenas para os campos em que deseja um comportamento especial (por exemplo, "store": true, "index": "not_analyzed") ou todos os campos. Consulte os documentos de mapeamento para obter mais detalhes.
precisa saber é o seguinte
3
campos não é mais suportado em versões mais recentes. uso stored_fields vez :)
Sachin Sharma
88

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].

Markus Coetzee
fonte
Fiz o truque para mim. Eu tive um problema ao retornar geo_point usando "fields", mas "_source" funciona muito bem, obrigado!
Yonnaled
23
For the ES versions 5.X and above you can a ES query something like this

    GET /.../...
    {
      "_source": {
        "includes": [ "FIELD1", "FIELD2", "FIELD3" ... " ]
      },
      .
      .
      .
      .
    }
Pinkesh Sharma
fonte
12

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!

woltob
fonte
7
here you can specify whichever field you want in your output and also which you don't.

  POST index_name/_search
    {
        "_source": {
            "includes": [ "field_name", "field_name" ],
            "excludes": [ "field_name" ]
        },
        "query" : {
            "match" : { "field_name" : "value" }
        }
    }
Gaurav
fonte
7

response_filtering

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.

https://stackoverflow.com/a/35647027/844700

The Demz
fonte
5

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
            }
        }
    ]
}

}

Ironluca
fonte
Isso é muito útil para mim.
Thusitha Indunil 5/11/19
4

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"
        },....
      }
    ]
  }
}
RCP
fonte
2

Em java, você pode usar o setFetchSource assim:

client.prepareSearch(index).setTypes(type)
            .setFetchSource(new String[] { "field1", "field2" }, null)
user1693371
fonte
2

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 namee scorepode 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
Yao Pan
fonte
0

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;
}
Doi
fonte