Эластичный запрос NEST DateRange кажется относительно медленным - PullRequest
0 голосов
/ 12 октября 2019

Я новичок в Elastic. Я пытаюсь сделать проверку концепции по профессиональным причинам. Пока что я очень впечатлен. Я проиндексировал кучу данных и выполнил несколько запросов - почти все из них очень быстрые (палец вверх).

Единственная проблема, с которой я сталкиваюсь, заключается в том, что мой запрос к диапазону дат выглядит относительно медленным по сравнению сна все мои другие вопросы. Мы говорим 1000 мс + по сравнению с <100 мс для всего остального. </p>

Я использую библиотеку NEST .NET.

Моя структура документа выглядит следующим образом:

{ 
   "tourId":"ABC123",
   "tourName":"Super cool tour",
   "duration":12,
   "countryCode":"MM",
   "regionCode":"AS",
   ...
   "availability":[ 
      { 
         "startDate":"2021-02-01T00:00:00",
         ...
      },
      { 
         "startDate":"2021-01-11T00:00:00",
         ...
      }
   ]
}

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

Я пробовал следующие два запроса:

var response = await elastic.SearchAsync<Tour>(s => s
    .Query(q => q
        .Nested(n => n
            .Path(p => p.Availability)
            .Query(nq => nq
                .DateRange(r => r
                    .Field(f => f.Availability.First().StartDate)
                    .GreaterThanOrEquals(new DateTime(2020, 07, 01))
                    .LessThan(new DateTime(2020, 08, 01))
                )
            )
        )
    )
    .Size(20)
    .Source(s => s.IncludeAll().Excludes(e => e.Fields(f => f.Availability)))
);

Я в основном следовал примеру на их документации здесь: https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/writing-queries.html#structured-search но яне уверен, что это лучший способ для меня достичь этого. Это просто, что диапазон дат, естественно, медленнее, чем другие запросы, или я просто делаю это неправильно?!

РЕДАКТИРОВАТЬ:

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

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

Запрос:

var response = await elastic.SearchAsync<Tour>(s => s
    .Query(q => q
        .Nested(n => n
            .Path(p => p.Availability)
            .Query(nq => nq
                .Term(t => t
                    .Field(f => f.Availability.First().YearMonth)
                    .Value(202007)
                )
            )
        )
    )
    .Size(20)
    .Source(s => s.IncludeAll().Excludes(e => e.Fields(f => f.Availability)))
    .Profile()
);

Профиль:

{ 
   "Shards":[ 
      { 
         "Aggregations":[ 

         ],
         "Id":"[pr4Os3Y7RT-gXRWR0gxoEQ][tours][0]",
         "Searches":[ 
            { 
               "Collector":[ 
                  { 
                     "Children":[ 
                        { 
                           "Children":[ 

                           ],
                           "Name":"SimpleTopDocsCollectorContext",
                           "Reason":"search_top_hits",
                           "TimeInNanoseconds":6589867
                        }
                     ],
                     "Name":"CancellableCollector",
                     "Reason":"search_cancelled",
                     "TimeInNanoseconds":13981165
                  }
               ],
               "Query":[ 
                  { 
                     "Breakdown":{ 
                        "Advance":5568,
                        "BuildScorer":2204354,
                        "CreateWeight":25661,
                        "Match":0,
                        "NextDoc":3650375,
                        "Score":3795517
                     },
                     "Children":null,
                     "Description":"ToParentBlockJoinQuery (availability.yearMonth:[202007 TO 202007])",
                     "TimeInNanoseconds":9686512,
                     "Type":"ESToParentBlockJoinQuery"
                  }
               ],
               "RewriteTime":36118
            }
         ]
      }
   ]
}

1 Ответ

1 голос
/ 13 октября 2019

Тем не менее, это похоже на проблему оптимизации структуры данных: не меняя слишком много, вы можете преобразовать все доступные даты в метку времени Unix, а затем использовать Запрос диапазона (быстрые советы по конвертации в C # можно найти здесь ).

Другой способ - создавать индексы ежемесячно (или еженедельно, ежегодно в зависимости от ваших данных), а перед выполнением запроса отфильтровывать индексы, то есть запрашивать только те индексы, которые вам нужны. Это будет означать размещение одинаковых списков в нескольких индексах (дубликаты документов в нескольких индексах) в зависимости от доступности месяца / дня.

Разделение данных временной метки (временных рядов) на определенную гранулярность индекса является обычной практикой в ​​ES. Подробнее здесь .

Последнее будет означать, что вы будете фильтровать по полю DateTime, а не по массиву меток времени.

Идентификатор лично идет со вторым вариантом.

...