diff --git a/script/harvester/harvester.sh b/script/harvester/harvester.sh new file mode 100755 index 0000000..6652386 --- /dev/null +++ b/script/harvester/harvester.sh @@ -0,0 +1,143 @@ +# URL de base de l'API ISTEX +ISTEX_API=https://api.istex.fr/document + +# Fonction pour récupérer une facette depuis l'API ISTEX +function fetch_facet() { + query="$1" + facet="$2" + # Appel à l'API ISTEX avec curl, en spécifiant la requête et la facette + response=$(curl --silent --get \ + --data-urlencode "q=$query" \ + --data-urlencode "facet=$facet[*]" \ + $ISTEX_API \ + ) + + # Formatage de la réponse en JSON et passage à la fonction process_bucket + echo "$response" | jq -c --arg facet "$facet" --arg query "$query" '{"facet": $facet, "query": $query, "response": .}' | process_bucket +} + +# Fonction pour traiter les buckets de données agrégées par facettes +function process_bucket { + input=$(cat) # Lecture de l'entrée JSON + # Utilisation de jq pour reformater les données de la réponse agrégée + echo "$input" | jq -c ' + .facet as $facet | .query as $query | + { + facet: $facet, + query: $query, + response: ( + .response.aggregations[$facet].buckets | map({nb: .docCount, ($facet): .key}) + ) + } + ' +} + +# Fonction pour gérer les requêtes imbriquées pour les facettes parentes +function nested_request { + local facet="$1" + local input=$(cat) + + # Si l'entrée est vide, retourner une chaîne vide + if [ -z "$input" ]; then + echo "" + return + fi + + local results="" + + # Boucle sur chaque ligne d'entrée JSON + while IFS= read -r line; do + local parent_facet=$(echo "$line" | jq -r '.facet') + local values=$(echo "$line" | jq -rc '.response[]') + local previous_query=$(echo "$line" | jq -r '.query') + + # Pour chaque valeur de la réponse, construire une nouvelle requête + for value in $values; do + local query=$(echo "$value" | jq -r --arg facet "$parent_facet" --arg query "$previous_query" '"\($query) AND \($facet):\"\(.[$facet])\""') + # Appeler fetch_facet avec la nouvelle requête et la facette actuelle + fetch_facet "$query" "$facet" | merge_parent_data_values "$value" + done + + done <<< "$input" # Alimenter l'entrée depuis le flux de données +} + +# Fonction pour fusionner les données des requêtes parentes et actuelles +function merge_parent_data_values { + local current="$1" + local parent=$(cat) + + # Utiliser jq pour fusionner les données actuelles dans la structure des données parentes + jq -c -n --argjson current "$current" --argjson parent "$parent" '$parent | .response = ([.response[] | . * ($current| del(.nb)) ])' +} + +# Fonction pour ajouter un horodatage à la sortie JSON +function stamp { + jq -c '{"date": (now | todate | split("T")[0] ) } + .' +} + +# Fonction pour aplatir la réponse JSON +function flatten_response { + jq -c '.response[]' +} + +# Fonction pour ajouter un champ de type à la sortie JSON +function type { + type="$1" + jq -c --arg type "$type" '{"type": $type } + .' +} + +# Fonction pour renommer certaines clés à partir d'un mapping +function clean_keys { + jq -c ' + { + "accessCondition.value": "access_condition", + "corpusName": "corpus", + "categories.scienceMetrix": "category", + "categories.inist": "category", + "categories.scopus": "category", + "categories.wos": "category" + } as $mapping | + with_entries(.key = ($mapping[.key]? // .key)) + ' +} + +# Fonction principale pour gérer les requêtes simples et imbriquées +function handle_request { + local base_query="$1" + local base_facet="$2" + local nested_facets="$3" + local type_name="$4" + + # Appeler fetch_facet avec la requête de base et la facette de base + local input=$(fetch_facet "$base_query" "$base_facet") + + # Si des facettes imbriquées sont spécifiées, traiter chaque facette imbriquée + if [ -n "$nested_facets" ]; then + for facet in $nested_facets; do + input=$(echo "$input" | nested_request "$facet") + done + fi + + # Aplatir la réponse, ajouter le type spécifié et un horodatage + echo "$input" | flatten_response | type "$type_name" | stamp | clean_keys +} + +handle_request "*" "corpusName" "" "corpus.nb_doc" +handle_request "*" "language" "" "istex.languages" +handle_request "*" "accessCondition.value" "" "istex.access_condition" +handle_request "*" "enrichments.type" "" "istex.enrichments" +handle_request "*" "host.genre" "" "istex.genre" +handle_request "*" "categories.inist" "" "istex.categories.inist" +handle_request "*" "categories.scopus" "" "istex.categories.scopus" +handle_request "*" "categories.scienceMetrix" "" "istex.categories.scienceMetrix" +handle_request "*" "categories.wos" "" "istex.categories.wos" + +handle_request "*" "corpusName" "accessCondition.value" "corpus.access_condition" +handle_request "*" "corpusName" "enrichments.type" "corpus.enrichment" +handle_request "*" "corpusName" "host.genre" "corpus.genre" +handle_request "*" "corpusName" "categories.inist" "corpus.category.inist" +handle_request "*" "corpusName" "categories.scopus" "corpus.category.scopus" +handle_request "*" "corpusName" "categories.scienceMetrix" "corpus.category.scienceMetrix" +handle_request "*" "corpusName" "categories.wos" "corpus.category.wos" +handle_request "*" "corpusName" "genre" "corpus.genre" +handle_request "*" "corpusName" "language language" "corpus.enrichment.lang"