Cet article est une suite de Utilisation de l'API Java Elasticsearch (enregistrement BulkRequest). Voir ci-dessus pour les exigences, la structure des données, etc.
D'ailleurs, je souhaite traiter diverses données enregistrées en Bulk.
――Je souhaite afficher les 10 meilleurs classements quotidiens des ventes. ――Je souhaite pouvoir changer la plage de dates par jour, semaine, mois, etc. ――Je souhaite pouvoir modifier le nombre de classements des ventes. ――Je veux pouvoir le voir séparément par général et par genre.
Kibana
Vous pouvez maintenant consulter le TOP 5 d'un jour particulier.
La configuration ci-dessus peut être exprimée comme une requête comme suit.
GET sample-ranking-qiita-*/_search
{
"aggs": {
"range": {
"date_range": {
"field": "execDate",
"ranges": [
{
"from": "2018/01/15T00:00:00+09:00",
"to": "2018/01/15T23:59:59+09:00"
}
]
},
"aggs": {
"title_rate": {
"terms": {
"field": "title.keyword",
"size": 5,
"order": {
"sum_rate": "desc"
}
},
"aggs": {
"sum_rate": {
"sum": {
"field": "rate"
}
}
}
}
}
}
}
}
N'est-il pas un peu difficile de voir la nidification des aggs? Les trois agrégats suivants sont définis.
sum_rate
par title
dans l'ordre décroissant avec le nom title_rate
SQL
Pour référence, c'est l'image de SQL. (Je ne l'ai pas essayé, donc je suis désolé si je fais une erreur)
ranking.sql
SELECT
ranking
, title
, sum_rate
FROM (
select
ROW_NUMBER() OVER (ORDER BY sum_rate DESC) AS ranking
, tb1.title
, tb1.sum_rate
FROM (
SELECT
title
, SUM(rate) as sum_rate
FROM
tbl_ranking
WHERE
execDate >= '2018/01/15T00:00:00+09:00'
AND execDate <= '2018/01/15T23:59:59+09:00'
GROUP BY
title
) tb1
)
WHERE
ranking <= 5
Lorsque j'obtiens le résultat de la requête, le résultat de aggs est imbriqué dans la balise ʻaggregations. La liste dans la balise
buckets` est la liste de résultats pour chaque agrégation.
Les mêmes titres affichés dans Kibana sont alignés. La valeur totale du taux correspond également.
{
"took": 426,
"timed_out": false,
"_shards": {
"total": 15,
"successful": 15,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 24800,
"max_score": 1,
"hits": [
(Omis)
]
},
"aggregations": {
"range": {
"buckets": [
{
// 3. title_Plage de dates agrégée du taux------------------------------
"key": "2018/01/14T15:00:00+0000-2018/01/15T14:59:59+0000",
"from": 1515942000000,
"from_as_string": "2018/01/14T15:00:00+0000",
"to": 1516028399000,
"to_as_string": "2018/01/15T14:59:59+0000",
"doc_count": 400,
// 2.titre une autre somme_ordre décroissant des taux------------------------------
"title_rate": {
"doc_count_error_upper_bound": -1,
"sum_other_doc_count": 380,
"buckets": [
{
"key": "Nouvelle ouverture",
"doc_count": 4,
"sum_rate": {
// 1.taux total------------
"value": 355
}
},
{
"key": "Lycéen",
"doc_count": 4,
"sum_rate": {
"value": 337
}
},
{
"key": "Test intermédiaire",
"doc_count": 4,
"sum_rate": {
"value": 333
}
},
{
"key": "La vérité de l'hôte",
"doc_count": 4,
"sum_rate": {
"value": 292
}
},
{
"key": "Un moment du match",
"doc_count": 4,
"sum_rate": {
"value": 292
}
}
]
}
}
]
}
}
}
Java-API
Maintenant, obtenons la requête ci-dessus avec Java-API.
AggsSampleViewer.java
public class AggsSampleViewer {
private static Logger logger = LoggerFactory.getLogger(AggsSampleViewer.class);
//Format d'index année / mois(yyyyMM)
private static DateTimeFormatter YM_INDEX_FORMATTER;
//Format de la date d'exécution(yyyy/MM/dd'T'HH:mm:ss+09:00)
private static DateTimeFormatter DT_INDEX_FORMATTER;
//Diverses informations de réglage
QiitaSettingBean setting;
/**
*constructeur
* @paramètres de réglage informations de réglage
*/
public AggsSampleViewer(QiitaSettingBean setting) {
super();
this.setting = setting;
DT_INDEX_FORMATTER = DateTimeFormatter.ofPattern(setting.getElasticearch().getExecDateFormat());
YM_INDEX_FORMATTER = DateTimeFormatter.ofPattern(setting.getElasticearch().getIndexYmFormat());
}
/**
*Exécution du processus d'acquisition
*
* @param subIndex Nom du sous-index(Nul au moment de l'acquisition totale)
* @throws Exception
*/
public void execute(String subIndex) throws Exception {
//Créer un client pour gérer ELS en Java
// setting.getElasticearch().getAddress():adresse IP
// setting.getElasticearch().getPort():numéro de port(Généralement 9300)
TransportClient client = new PreBuiltTransportClient(Settings.EMPTY).addTransportAddress(
new InetSocketTransportAddress(InetAddress.getByName(setting.getElasticearch().getAddress()),
setting.getElasticearch().getPort()));
//Génération d'index pour la recherche(Lorsque le sous-index est spécifié, le sous est également inclus)
String searchIndex = setting.getElsImport().getIndex();
if (StringUtils.isNotEmpty(subIndex)) {
searchIndex = searchIndex + "-" + subIndex;
}
searchIndex += "*";
logger.debug("■■■ Index cible de la recherche: " + searchIndex);
// sum_Aggs for rate: Calculez la valeur totale du taux
AggregationBuilder sumRateAggs = AggregationBuilders.sum("sum_rate").field("rate");
// title_Aggs for rate: Ordre décroissant du taux par titre
AggregationBuilder titleRateAggs = AggregationBuilders.terms("title_rate")
//Agréger par titre
.field("title.keyword")
// setting.getRankingLimit():Numéro de classement
.size(setting.getRankingLimit())
//L'ordre d'affichage est la somme_ordre décroissant de taux
.order(Order.aggregation("sum_rate", false))
//aux subaggs, sum_Ajout d'Aggs pour le taux
.subAggregation(sumRateAggs)
;
//Aggs pour la plage de dates
AggregationBuilder dateRangeAggs = AggregationBuilders.dateRange("range")
//La cible de la plage de dates est la date d'exécution du traitement
.field("execDate")
//Définissez la plage de dates du jour avant 0h00 le jour cible de traitement à 0h00 le jour
//Exemple) setting.getNow(): 2018/01/16 13:20:35
// from:2018/01/15 00:00:00
// to :2018/01/16 00:00:00
.addRange(
setting.getNow().minusDays(1).truncatedTo(ChronoUnit.DAYS).format(DT_INDEX_FORMATTER)
, setting.getNow().truncatedTo(ChronoUnit.DAYS).format(DT_INDEX_FORMATTER)
)
//subaggs, titre_Ajout d'Aggs pour le taux
.subAggregation(titleRateAggs)
;
//Requête entière
SearchRequestBuilder requestBuilder = client.prepareSearch(searchIndex)
.addAggregation(dateRangeAggs);
//Obtenez les résultats de la recherche
SearchResponse res = requestBuilder.get();
//Obtenez le résultat de Aggs de la requête entière
for (Aggregation aggs : res.getAggregations()) {
logger.debug("aggs name: "+ aggs.getName());
}
//[Aggs pour la plage de dates](type:date_range) ----------------
InternalDateRange resDateRangeAggs = res.getAggregations().get("range");
//Vérifiez le compartiment dans Aggs pour la plage de dates
for (InternalDateRange.Bucket dateRangeBucket : resDateRangeAggs.getBuckets()) {
//clé et doc_le nombre peut être obtenu avec n'importe quel Bucket
logger.debug("* resDateRangeAggs bucket key: "+ dateRangeBucket.getKey());
logger.debug("* resDateRangeAggs bucket doc_count: "+ dateRangeBucket.getDocCount());
//De et À peuvent être obtenus car ils font référence au compartiment pour la plage de dates.
logger.debug("* resDateRangeAggs bucket from: "+ dateRangeBucket.getFromAsString());
logger.debug("* resDateRangeAggs bucket to: "+ dateRangeBucket.getToAsString());
//Vérifier les résultats Aggs dans Aggs pour la plage de dates
for (Aggregation aggs : dateRangeBucket.getAggregations()) {
logger.debug("* resDateRangeAggs bucket aggs: "+ aggs.getName());
}
// 【title_Aggs pour taux](type:terms) ----------------
Terms resTitleRateAggs = dateRangeBucket.getAggregations().get("title_rate");
// title_Vérifiez le seau en Aggs pour le taux
for (Terms.Bucket termBucket : resTitleRateAggs.getBuckets()) {
logger.debug("** resTitleRateAggs bucket key: "+ termBucket.getKey());
logger.debug("** resTitleRateAggs bucket doc_count: "+ termBucket.getDocCount());
// title_Confirmation du résultat Aggs pour le taux
for (Aggregation aggs : termBucket.getAggregations()) {
logger.debug("** resTitleRateAggs bucket aggs: "+ aggs.getName());
}
// 【sum_Aggs pour taux](type:sum) ----------------
Sum resSumRateAggs = termBucket.getAggregations().get("sum_rate");
//Il n'y a pas d'Aggs dans Sum et vous pouvez obtenir des résultats de somme
logger.debug("*** resSumRateAggs sum name: "+ resSumRateAggs.getName());
logger.debug("*** resSumRateAggs sum value: "+ resSumRateAggs.getValueAsString());
}
}
}
}
Nous définirons Aggs avec la même structure imbriquée que la requête. Est-il un peu difficile de savoir quel Aggs utiliser et quel Bucket est retourné ^^; Il est préférable de vérifier la formule dans ce domaine.
https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-aggs.html
L'exécution se fait comme ça.
main.java
AggsSampleViewer viewer = new AggsSampleViewer(setting);
//Génération d'informations de classement global
logger.debug("■ Classement général----------------------------------------");
viewer.execute(null);
//Génération d'informations de classement Shonen
logger.debug("■ Classement des garçons----------------------------------------");
viewer.execute("boy");
■ Classement général----------------------------------------
■■■ Index cible de la recherche: sample-ranking-qiita*
aggs name: range
* resDateRangeAggs bucket key: 2018/01/14T15:00:00+0000-2018/01/15T15:00:00+0000
* resDateRangeAggs bucket doc_count: 400
* resDateRangeAggs bucket from: 2018/01/14T15:00:00+0000
* resDateRangeAggs bucket to: 2018/01/15T15:00:00+0000
* resDateRangeAggs bucket aggs: title_rate
** resTitleRateAggs bucket key:Nouvelle ouverture
** resTitleRateAggs bucket doc_count: 4
** resTitleRateAggs bucket aggs: sum_rate
*** resSumRateAggs sum name: sum_rate
*** resSumRateAggs sum value: 355.0
** resTitleRateAggs bucket key:Lycéen
** resTitleRateAggs bucket doc_count: 4
** resTitleRateAggs bucket aggs: sum_rate
*** resSumRateAggs sum name: sum_rate
*** resSumRateAggs sum value: 337.0
** resTitleRateAggs bucket key:Test intermédiaire
** resTitleRateAggs bucket doc_count: 4
** resTitleRateAggs bucket aggs: sum_rate
*** resSumRateAggs sum name: sum_rate
*** resSumRateAggs sum value: 333.0
** resTitleRateAggs bucket key:La vérité de l'hôte
** resTitleRateAggs bucket doc_count: 4
** resTitleRateAggs bucket aggs: sum_rate
*** resSumRateAggs sum name: sum_rate
*** resSumRateAggs sum value: 292.0
** resTitleRateAggs bucket key:Un moment du match
** resTitleRateAggs bucket doc_count: 4
** resTitleRateAggs bucket aggs: sum_rate
*** resSumRateAggs sum name: sum_rate
*** resSumRateAggs sum value: 292.0
■ Classement des garçons----------------------------------------
■■■ Index cible de la recherche: sample-ranking-qiita-boy*
aggs name: range
* resDateRangeAggs bucket key: 2018/01/14T15:00:00+0000-2018/01/15T15:00:00+0000
* resDateRangeAggs bucket doc_count: 141
* resDateRangeAggs bucket from: 2018/01/14T15:00:00+0000
* resDateRangeAggs bucket to: 2018/01/15T15:00:00+0000
* resDateRangeAggs bucket aggs: title_rate
** resTitleRateAggs bucket key:Lycéen
** resTitleRateAggs bucket doc_count: 4
** resTitleRateAggs bucket aggs: sum_rate
*** resSumRateAggs sum name: sum_rate
*** resSumRateAggs sum value: 337.0
** resTitleRateAggs bucket key:Knockout et épisode 2
** resTitleRateAggs bucket doc_count: 4
** resTitleRateAggs bucket aggs: sum_rate
*** resSumRateAggs sum name: sum_rate
*** resSumRateAggs sum value: 287.0
** resTitleRateAggs bucket key:Résultats en avant et apparence
** resTitleRateAggs bucket doc_count: 4
** resTitleRateAggs bucket aggs: sum_rate
*** resSumRateAggs sum name: sum_rate
*** resSumRateAggs sum value: 278.0
** resTitleRateAggs bucket key:cœur
** resTitleRateAggs bucket doc_count: 4
** resTitleRateAggs bucket aggs: sum_rate
*** resSumRateAggs sum name: sum_rate
*** resSumRateAggs sum value: 267.0
** resTitleRateAggs bucket key:Championnat
** resTitleRateAggs bucket doc_count: 3
** resTitleRateAggs bucket aggs: sum_rate
*** resSumRateAggs sum name: sum_rate
*** resSumRateAggs sum value: 260.0
J'ai pu obtenir les mêmes résultats que Kibana et la requête!
Ah, c'est naturel comme requête d'agrégation, mais avec ʻaggs, seuls les champs utilisés pour l'agrégation peuvent être acquis, et d'autres champs (auteurs, etc. dans ce cas) ne peuvent pas être acquis. Ce serait bien si je pouvais obtenir le résultat de l'association avec le champ dans ʻaggs
d'un seul coup avec query
, mais cela ne semble pas être le cas.
Si vous augmentez la «taille» de la «requête», la possibilité de l'obtenir augmentera, mais je pense que la limite supérieure de la «taille» de la «requête» est «10000», donc vous pouvez certainement l'obtenir dans cette plage. Si vous n'êtes pas sûr, il vaut mieux l'obtenir tranquillement avec une autre requête.
Le genre de livre est défini comme un sous-index pour faciliter la réduction de la portée de la recherche. Je me suis demandé si la réduction de l'indice réduirait au maximum le fardeau lors de la recherche d'une fourchette à long terme. Bien entendu, il peut être inclus dans la condition de requête.
AggsSampleViewer2.java
//Requête pour le filtrage par genre
QueryBuilder queryBuilder = QueryBuilders.termQuery("index", subIndex);
//Requête entière
SearchRequestBuilder requestBuilder = client.prepareSearch(searchIndex)
.addAggregation(dateRangeAggs);
//Ajouter une requête si un sous-index est spécifié
if (StringUtils.isNotEmpty(subIndex)) {
requestBuilder.setQuery(queryBuilder);
}
Vous pouvez également affiner en utilisant Query Builder
comme ceci.
Si vous souhaitez modifier la plage de dates, par exemple hebdomadaire ou mensuelle, basculez dans ʻaddRange de
dateRangeAggs`.
J'ai également créé des informations de définition de plage car je souhaite pouvoir les modifier librement à partir des paramètres.
AggsSampleViewer3.java
//Aggs pour la plage de dates
AggregationBuilder dateRangeAggs = AggregationBuilders.dateRange("range")
//La cible de la plage de dates est la date d'exécution du traitement
.field("execDate")
//Définir la plage de dates entre De et A de la plage de recherche
//Exemple)De 10 jours avant la date d'exécution à minuit le jour d'exécution
//"searchRange": {
// "from": "-10",
// "fromChrono": "days",
// "to": "0",
// "toChrono": "days"
//}
.addRange(
DT_INDEX_FORMATTER.format(
//Du paramètre de plage de recherche à la date d'exécution est ajouté en unités d'unités spécifiées.
setting.getNow()
.plus(setting.getSearchRange().getFrom()
, setting.getSearchRange().findFromChronoUnit())
//Coupé après la journée (faites-le exactement à 0 heure)
.truncatedTo(ChronoUnit.DAYS))
, DT_INDEX_FORMATTER.format(
//Ajouter le À du paramètre de plage de recherche à la date d'exécution dans l'unité d'unité spécifiée
setting.getNow()
.plus(setting.getSearchRange().getTo()
, setting.getSearchRange().findToChronoUnit())
//Coupé après la journée (faites-le exactement à 0 heure)
.truncatedTo(ChronoUnit.DAYS))
)
//subaggs, titre_Ajout d'Aggs pour le taux
.subAggregation(titleRateAggs)
;
RangeBean.java
public class RangeBean {
private int from;
private String fromChrono;
private int to;
private String toChrono;
public ChronoUnit findFromChronoUnit() {
return findChronoUnit(fromChrono);
}
public ChronoUnit findToChronoUnit() {
return findChronoUnit(toChrono);
}
/**
*Changer la chaîne Chrono en unité
*
* @param chrono
* @return
*/
public ChronoUnit findChronoUnit(String chrono) {
if (StringUtils.equals(chrono, "days")) {
return ChronoUnit.DAYS;
}
if (StringUtils.equals(chrono, "weeks")) {
return ChronoUnit.WEEKS;
}
if (StringUtils.equals(chrono, "months")) {
return ChronoUnit.MONTHS;
}
if (StringUtils.equals(chrono, "years")) {
return ChronoUnit.YEARS;
}
return null;
}
//(Omis)
}
Vous pouvez désormais spécifier la plage à votre guise, mensuellement ou sur trois ans.
La prochaine fois, j'aimerais écrire comment spécifier et obtenir une requête avec Java-API.