Сортировка и запрос запроса на основе поля даты, которое может не существовать

#elasticsearch

#elasticsearch

Вопрос:

Требование: я хочу выполнить запрос и отсортировать по date field , которое может не существовать. Поле даты записей не существует, все должно быть включено первым, тогда записи, date field значение которых меньше 1600230168278 , будут включены туда позже. Сначала будут упорядочены те записи, которые не существуют date field затем date ascending

Отображение и образцы данных:

 PUT my_index
{
  "mappings": {
    "_doc": {
      "properties": {
        "date": {
          "type": "date"
        },
        "name": {
          "type": "text"
        }
      }
    }
  }
}

PUT my_index/_doc/1
{
  "date": 1546300800000
} 

PUT my_index/_doc/2
{
  "date": 1577836800000
} 

PUT my_index/_doc/3
{
  "date": 1609459200000
} 

PUT my_index/_doc/4
{
  "name": "Arif Mahmud Rana"
} 
  

Мой запрос:

 {
  "query": {
    "bool": {
      "must": {
        "function_score": {
          "functions": [
            {
              "filter": {
                "exists": {
                  "field": "date"
                }
              },
              "weight": 0.5
            }
          ],
          "query": {
            "match_all": {}
          }
        }
      },
      "filter": {
        "bool": {
          "minimum_should_match": 1,
          "should": [
            {
              "bool": {
                "must": [
                  {
                    "exists": {
                      "field": "date"
                    }
                  },
                  {
                    "range": {
                      "date": {
                        "lt": 1600230168278
                      }
                    }
                  }
                ]
              }
            },
            {
              "bool": {
                "must_not": {
                  "exists": {
                    "field": "date"
                  }
                }
              }
            }
          ]
        }
      }
    }
  },
  "sort": [
    {
      "_score": "desc"
    },
    {
      "date": "asc"
    }
  ],
  "size": 100
}
  

Результат запроса:

 {
  "took" : 4,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 3,
    "max_score" : null,
    "hits" : [
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 1.0,
        "_source" : {
          "name" : "Arif Mahmud Rana"
        },
        "sort" : [
          1.0,
          9223372036854775807
        ]
      },
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.5,
        "_source" : {
          "date" : 1546300800000
        },
        "sort" : [
          0.5,
          1546300800000
        ]
      },
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.5,
        "_source" : {
          "date" : 1577836800000
        },
        "sort" : [
          0.5,
          1577836800000
        ]
      }
    ]
  }
}
  

Это отлично работает для этого простого индекса с меньшим количеством данных, но при работе с большим индексом мой эластичный узел выходит из строя.

Эластичная версия: 6.8.5

Фактический индекс: 3048140( docs.count ), 1073559( docs.deleted ), 1,3 ГБ ( store.size ) и 1,3 ГБ ( pri.store.size )

Любая помощь или идея будут полезны TIA.

Ответ №1:

Я считаю, что пользовательская оценка во всех документах, не имеющих поля даты в большом индексе, вызывает проблему.

Вот способ, которым это можно сделать для достижения вашей цели использования, используя missing для определения критериев сортировки для документов с отсутствующим полем сортировки.

 GET test/_search
{"query":{"match_all":{}}}

PUT /test
{
    "mappings": {
      
            "properties": {
               
                "name": {
                    "type": "keyword"
                },
                "age": { "type": "integer" }
            }
        
    }
}

POST test/_doc
{
  "name": "shahin",
  "age": 234
}


POST test/_doc
{
  "name": "karim",
  "age": 235
}


POST test/_doc
{
  "name": "rahim"
}

POST test/_search
{
  "query": {
        "bool": {
          "should": [
            {
              "bool": {
                "must": 
                  {
                    "range": {
                      "age": {
                        "lt": 250
                      }
                    }
                  }
              }
            },
            {
              "bool": {
                "must_not": {
                  "exists": {
                    "field": "age"
                  }
                }
              }
            }
          ]
        }
      },
  "sort": [
    { "age" : {"missing" : "_first", "order": "asc"}}
  ],
  "size": 100
}
  

Комментарии:

1. Шахин вхай большое спасибо, это действительно значительно улучшило производительность

Ответ №2:

Я добавил некоторую оптимизацию, которая может помочь другим. Я индексировал свой производственный индекс по этому индексу. Мне пришлось выполнять поиск / запрос, а затем перебирать эти данные и индексировать в моем производственном индексе. Вот мой производственный запрос.

 GET /my_index/_search?filter_path=hits.hits._id,hits.hits._source
{
  "query": {
    "bool": {
      "filter": {
        "bool": {
          "minimum_should_match": 1,
          "should": [
            {
              "range": {
                "lastModified": {
                  "lte": 1600314822988
                }
              }
            },
            {
              "bool": {
                "must_not": {
                  "exists": {
                    "field": "lastModified"
                  }
                }
              }
            }
          ]
        }
      }
    }
  },
  "sort": [
    {
      "indexed": {
        "order": "asc",
        "missing": "_first"
      }
    },
    {
      "lastModified": {
        "order": "asc",
        "missing": "_first"
      }
    }
  ],
  "size": 100
}
  

Я использовал filter over should , поскольку моему запросу не нужна оценка по совпадающим элементам. Также я использовал filter_path для получения только обязательных полей. После добавления этой оптимизации мой запрос был как минимум на 4 секунды быстрее.