我是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
}
]
}
]
}
答案 0 :(得分:1)
尽管如此,这似乎是一个数据结构优化问题: 无需过多更改,您就可以将所有可用日期转换为Unix时间戳,然后使用Range query(可以在here中找到C#中的快速转换技巧)。
另一种方法是创建每月(或每周,每年取决于您的数据)索引,并在执行查询之前过滤掉索引,即仅查询所需的索引。这意味着根据可用月/日将相同的列表放入多个索引(多个索引中的重复文档)。
在ES中,按照特定的索引粒度分隔时间戳(时间序列)数据是一种常见的做法。更多信息here。
后者将意味着您将过滤DateTime字段,而不是时间戳数组。
Id个人选择第二个选项。