2015-07-20 3 views
2

Я хотел бы иметь возможность запрашивать текст, но также получать только результаты с максимальным значением некоторого целочисленного поля в моих данных. Я прочитал документы об агрегатах и ​​фильтрах, и я не совсем понимаю, что я ищу.Как сделать запрос elasticsearch, который фильтрует максимальное значение поля?

Например, у меня есть некоторые повторяющиеся данные, которые индексируются одинаково, за исключением целочисленного поля - назовем это поле lastseen.

Так, в качестве примера, учитывая эти данные, введенные в elasticsearch:

// these two the same except "lastseen" field 
    curl -XPOST localhost:9200/myindex/myobject -d '{ 
    "field1": "dinner carrot potato broccoli", 
    "field2": "something here", 
    "lastseen": 1000 
    }' 

    curl -XPOST localhost:9200/myindex/myobject -d '{ 
    "field1": "dinner carrot potato broccoli", 
    "field2": "something here", 
    "somevalue": 100 
    }' 

    # and these two the same except "lastseen" field 
    curl -XPOST localhost:9200/myindex/myobject -d '{ 
    "field1": "fish chicken something", 
    "field2": "dinner", 
    "lastseen": 2000 
    }' 

    curl -XPOST localhost:9200/myindex/myobject -d '{ 
    "field1": "fish chicken something", 
    "field2": "dinner", 
    "lastseen": 200 
    }' 

Если я запрос для "dinner"

curl -XPOST localhost:9200/myindex -d '{ 
    "query": { 
     "query_string": { 
      "query": "dinner" 
     } 
    } 
    }' 

я получить 4 результаты обратно. Я хотел бы иметь фильтр, чтобы получить только два результата - только элементы с максимальным полем lastseen.

Это явно не прав, но мы надеемся, что это дает вам представление о том, что я после:

{ 
    "query": { 
     "query_string": { 
      "query": "dinner" 
     } 
    }, 
    "filter": { 
      "max": "lastseen" 
     } 

} 

Результаты будут выглядеть примерно так:

"hits": [ 
     { 
     ... 
     "_source": { 
      "field1": "dinner carrot potato broccoli", 
      "field2": "something here", 
      "lastseen": 1000 
     } 
     }, 
     { 
     ... 
     "_source": { 
      "field1": "fish chicken something", 
      "field2": "dinner", 
      "lastseen": 2000 
     } 
     } 
    ] 

обновление 1: Я попытался создать сопоставление, которое исключало индексацию lastseen. Это не сработало. Все еще получаю все 4 результата.

curl -XPOST localhost:9200/myindex -d '{ 
    "mappings": { 
     "myobject": { 
     "properties": { 
      "lastseen": { 
      "type": "long", 
      "store": "yes", 
      "include_in_all": false 
      } 
     } 
     } 
    } 
}' 

обновление 2: Я попробовал дедупликации со схемой AGG listed here, и это не сработало, но что более важно, я не вижу способ совместить это с поиском по ключевым словам.

+0

Что делать, если у вас есть два документы с 'lastseen: 2000', вы хотите, оба вернулись или один с' lastseen: 2000' и один с 'lastseen: 1000'? –

+0

Кроме того, что вы считаете дублирующим документом? Я вижу, что вы признаете этот тип документов как те, у которых есть одно и то же 'field1'. –

+0

@AndreiStefan дублированный документ будет иметь одинаковое поле1 и поле2. –

ответ

4

Не идеален, но я думаю, что это дает вам то, что вам нужно.

Изменить отображение вашего field1 поля, предполагая, что это тот, который вы используете, чтобы определить «дублировать» документы, например:

PUT /lastseen 
{ 
    "mappings": { 
    "test": { 
     "properties": { 
     "field1": { 
      "type": "string", 
      "fields": { 
      "raw": { 
       "type": "string", 
       "index": "not_analyzed" 
      } 
      } 
     }, 
     "field2": { 
      "type": "string" 
     }, 
     "lastseen": { 
      "type": "long" 
     } 
     } 
    } 
    } 
} 

смысла, вы добавляете .raw подпол, которое not_analyzed что означает его будет индексироваться так, как есть, не анализировать и не разбивать на термины. Это делается для того, чтобы сделать несколько «дублирование документов».

Затем вам нужно использовать terms агрегации на field1.raw (для дублей) и суб-агрегации top_hits, чтобы получить один документ для каждого field1 значения:

GET /lastseen/test/_search 
{ 
    "size": 0, 
    "query": { 
    "query_string": { 
     "query": "dinner" 
    } 
    }, 
    "aggs": { 
    "field1_unique": { 
     "terms": { 
     "field": "field1.raw", 
     "size": 2 
     }, 
     "aggs": { 
     "first_one": { 
      "top_hits": { 
      "size": 1, 
      "sort": [{"lastseen": {"order":"desc"}}] 
      } 
     } 
     } 
    } 
    } 
} 

Кроме того, что один документ, возвращаемый top_hits самый высокий lastseen (вещь сделана "sort": [{"lastseen": {"order":"desc"}}]).

Результаты вы получите обратно в них (под aggregations не hits):

... 
    "aggregations": { 
     "field1_unique": { 
     "doc_count_error_upper_bound": 0, 
     "sum_other_doc_count": 0, 
     "buckets": [ 
      { 
       "key": "dinner carrot potato broccoli", 
       "doc_count": 2, 
       "first_one": { 
        "hits": { 
        "total": 2, 
        "max_score": null, 
        "hits": [ 
         { 
          "_index": "lastseen", 
          "_type": "test", 
          "_id": "AU60ZObtjKWeJgeyudI-", 
          "_score": null, 
          "_source": { 
           "field1": "dinner carrot potato broccoli", 
           "field2": "something here", 
           "lastseen": 1000 
          }, 
          "sort": [ 
           1000 
          ] 
         } 
        ] 
        } 
       } 
      }, 
      { 
       "key": "fish chicken something", 
       "doc_count": 2, 
       "first_one": { 
        "hits": { 
        "total": 2, 
        "max_score": null, 
        "hits": [ 
         { 
          "_index": "lastseen", 
          "_type": "test", 
          "_id": "AU60ZObtjKWeJgeyudJA", 
          "_score": null, 
          "_source": { 
           "field1": "fish chicken something", 
           "field2": "dinner", 
           "lastseen": 2000 
          }, 
          "sort": [ 
           2000 
          ] 
         } 
        ] 
        } 
       } 
      } 
     ] 
     } 
    } 
+0

Спасибо. Это именно то, что я искал. –

Смежные вопросы