2

クエリ設計の問題に直面していて、問題に対する私のアプローチが不必要に複雑であるかどうかわからない:

私はファクトテーブルを持っています:

       Column   |            Type             |                       Modifiers                       
------------+-----------------------------+-------------------------------------------------------
 id         | integer                     | not null default nextval('messages_id_seq'::regclass)
 type       | character varying(255)      | 
 ts         | numeric                     | 
 text       | text                        | 
 score      | double precision            | 
 user_id    | integer                     | 
 channel_id | integer                     | 
 time_id    | integer                     | 
 created_at | timestamp without time zone | 
 updated_at | timestamp without time zone | 

現在、それに対していくつかの分析クエリを実行しています。そのうちの 1 つ (たとえば) は次のようになります。

  with intervals as (
  select 
    (select '09/27/2014'::date) + (n      || ' minutes')::interval start_time,
    (select '09/27/2014'::date) + ((n+60) || ' minutes')::interval end_time
      from generate_series(0, (24*60*7), 60 * 4) n
  )
  select 
    extract(epoch from i.start_time)::numeric * 1000 as ts, 
    extract(epoch from i.end_time)::numeric * 1000 as end_ts,
    sum(avg(messages.score)) over (order by i.start_time) as score

  from messages
  right join intervals i
    on messages.timestamp >= i.start_time and messages.timestamp < i.end_time

  where messages.timestamp between '09/27/2014' and '10/04/2014'

  group by i.start_time, i.end_time 
  order by i.start_time

おそらくわかるように、このクエリは、特定の時間バケット分布のメッセージの「スコア」属性の平均を計算し、それと並行してバケット全体の累積を計算します (ウィンドウを使用)。

次にやろうとしているのはmessages.text、各バケットの平均に最も近い上位 5 つ (たとえば) を見つけることです。

現在、私が持っている唯一の計画は次のとおりです。

1) Join messages with the time-buckets
2) Compute a score - avg(score) over (partition by start_time) as deviation and save it against each record of the joined relation
3) Compute a rank() over (order by deviation) as rank
4) Select where rank between 1 and 5

ウィンドウ関数内でウィンドウ関数を使用することを含む設計を考え出す最初の試みであり、それが機能(rank() over (partition by start_time, order by score - avg(score) over (partition by start_time))するかどうかを確認するつもりさえなかったので、これを命令的に段階的に書き留めた理由.

正しい方向に進んでいるかどうかについてアドバイスをいただけますか?

4

2 に答える 2

0

Whelp - これが私が持っていて、うまくいくように見えるものです:

批判の対象となっているのは、クエリの構造化、パフォーマンスの最適化、および冗長性です。^_^ (私が最終的に修正するすべてのねじれた間隔の計算の代わりに、時系列を直接生成するマイナス!)

with intervals as (
    select 
        (select '09/29/2014'::date) + (n      || ' minutes')::interval start_time,
        (select '09/29/2014'::date) + ((n+60) || ' minutes')::interval end_time
        from generate_series(0, (24*60*7), 60 * 4) n
), intervaled_messages as (
    select
        extract(epoch from i.start_time)::numeric * 1000 as ts, 
        extract(epoch from i.end_time)::numeric * 1000 as end_ts,
        abs(score - avg(score) over (partition by i.start_time)) as deviation
    from messages
    right join intervals i
        on messages.timestamp >= i.start_time and messages.timestamp < i.end_time
    where messages.timestamp between '09/29/2014' and '10/06/2014'
), ranked_messages as (
    select ts, end_ts, deviation, 
    rank() over (partition by ts order by deviation) as rank,
    row_number() over (partition by ts order by deviation) as row_number
    from intervaled_messages
)
select ts, end_ts, deviation, rank 
from ranked_messages 
where rank between 1 and 5
  and row_number between 1 and 5
order by ts;
于 2014-10-06T23:52:29.887 に答える
0

あなたが向かうべき方向(これは私の提案にすぎません):

  1. 平均スコアを取得します (すべてのレコードについて)
  2. 操作MINUS_(row score, avg(score))

-- This will leave you with values also positive and negative

  1. abs()同じ計算で、ステップ 2 からの各操作で使用します。
  2. rank()それらを適切に使用して注文する
  3. WHERE rank BETWEEN 1 AND 5
于 2014-10-06T09:48:08.157 に答える