弹性NEST DateRange查询似乎相对较慢

时间:2019-10-12 13:57:14

标签: c# elasticsearch asp.net-core nest elastic-stack

我是Elastic的新手。由于专业原因,我正在尝试进行概念验证。到目前为止,我印象深刻。我已经索引了一堆数据并运行了一些查询-几乎所有查询都非常快(竖起大拇指)。

我遇到的唯一问题是,与所有其他查询相比,我的日期范围查询似乎相对较慢。我们说的是1000ms +,而其他所有时间都是<100ms。

我正在使用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 个答案:

答案 0 :(得分:1)

尽管如此,这似乎是一个数据结构优化问题: 无需过多更改,您就可以将所有可用日期转换为Unix时间戳,然后使用Range query(可以在here中找到C#中的快速转换技巧)。

另一种方法是创建每月(或每周,每年取决于您的数据)索引,并在执行查询之前过滤掉索引,即仅查询所需的索引。这意味着根据可用月/日将相同的列表放入多个索引(多个索引中的重复文档)。

在ES中,按照特定的索引粒度分隔时间戳(时间序列)数据是一种常见的做法。更多信息here

后者将意味着您将过滤DateTime字段,而不是时间戳数组。

Id个人选择第二个选项。