web-dev-qa-db-fra.com

Comparaison de date dans Hive

Je travaille avec Hive et j'ai un tableau structuré comme suit:

CREATE TABLE t1 (
  id INT,
  created TIMESTAMP,
  some_value BIGINT
);

Je dois trouver chaque ligne dans t1 datant de moins de 180 jours. La requête suivante ne génère aucune ligne même si la table contient des données correspondant au prédicat de recherche.

select * 
from t1 
where created > date_sub(from_unixtime(unix_timestamp()), 180);

Quelle est la manière appropriée d'effectuer une comparaison de date dans Hive?

9
Jeremiah Peschka

Que diriez-vous:

where unix_timestamp() - created < 180 * 24 * 60 * 60

Le calcul des dates est généralement le plus simple si vous pouvez le faire avec les valeurs d’horodatage réelles.

Ou voulez-vous qu'il soit coupé uniquement des jours entiers? Ensuite, je pense que le problème réside dans la façon dont vous effectuez la conversion entre les ints et les chaînes. Essayer:

where created > unix_timestamp(date_sub(from_unixtime(unix_timestamp(),'yyyy-MM-dd'),180),'yyyy-MM-dd')

En parcourant chaque UDF:

  1. unix_timestamp() renvoie une int: heure actuelle en secondes depuis Epoch
  2. from_unixtime(,'yyyy-MM-dd') est converti en une chaîne du format donné, par exemple. '2012-12-28'
  3. date_sub(,180) soustrait 180 jours de cette chaîne et renvoie une nouvelle chaîne au même format.
  4. unix_timestamp(,'yyyy-MM-dd') reconvertit cette chaîne en un entier

Si tout cela devient trop poilu, vous pouvez toujours écrire un fichier UDF pour le faire vous-même.

13
Joe K

Alternativement, vous pouvez aussi utiliser datiff . Ensuite, la clause where serait
en cas d'horodatage de chaîne (format jdbc):

datediff(from_unixtime(unix_timestamp()), created) < 180;

en cas de temps Unix: 

datediff(from_unixtime(unix_timestamp()), from_unixtime(created)) < 180;
5
Lorand Bendig

Je pense que c’est peut-être un bogue Hive qui concerne le type timestamp. J'ai essayé de l'utiliser récemment et d'obtenir des résultats incorrects. Si je change votre schéma pour utiliser une chaîne au lieu de timestamp, et fournir des valeurs dans le 

aaaa-MM-jj HH: mm: ss

format, puis la requête de sélection a fonctionné pour moi.

Selon la documentation, Hive devrait être en mesure de convertir un BIGINT représentant des secondes d’époque en un horodatage, et que tous les fichiers UDF datetime existants fonctionnent avec le type de données d’horodatage. 

avec cette requête simple:

sélectionnez from_unixtime (unix_timestamp ()), transformez (unix_timestamp () en tant qu'horodatage ) à partir de test_tt limite 1;

Je m'attendrais à ce que les deux champs soient identiques, mais je reçois:

2012-12-29 00:47:43 1970-01-16 16: 52: 22.063

Je vois aussi d'autres bizarreries.

3
libjack

TIMESTAMP est en millisecondes
unix_timestamp est en secondes
Vous devez multiplier le RHS par 1000.

where created > 1000 * date_sub(from_unixtime(unix_timestamp()), 180);
3
user1089933

Après avoir examiné cela et fait référence à Date Difference moins de 15 minutes dans Hive j’ai trouvé une solution. Bien que je ne sois pas sûr de savoir pourquoi Hive n'effectue pas la comparaison de manière efficace sur les dates sous forme de chaînes (elles doivent trier et comparer lexicographe), la solution suivante fonctionne:

FROM (
    SELECT  id, value,
            unix_timestamp(created) c_ts, 
            unix_timestamp(date_sub(from_unixtime(unix_timestamp()), 180), 'yyyy-MM-dd') c180_ts
    FROM    t1
) x
JOIN t1 t ON x.id = t.id
SELECT  to_date(t.Created), 
        x.id, AVG(COALESCE(x.HighestPrice, 0)), AVG(COALESCE(x.LowestPrice, 0))
WHERE   unix_timestamp(t.Created) > x.c180_ts
GROUP BY to_date(t.Created), x.id ;
1
Jeremiah Peschka