--- title: "Functionsの設定" url: https://docs.catalyst.zoho.com/ja/tutorials/museum-finder/configure-functions/ description: "Catalyst Functionsを使用して、評価や旅行者タイプの条件に基づいて博物館を検索するMuseum Finderウェブアプリケーションをビルドし、Catalyst Circuitsを使用してワークフローを自動化します。" last_updated: 2026-03-05T06:13:24Z service: All Services type: tutorial related_links: - name: "Basic I/O Functions" url: /ja/serverless/help/functions/basic-io/ - name: "Advanced I/O Functions" url: /ja/serverless/help/functions/advanced-io/ - name: "Functionsディレクトリ構造" url: /ja/cli/v1/project-directory-structure/functions-directory --- # Functionsディレクトリの設定 次に、Functionsを設定してMuseum Finderアプリケーションのコーディングを開始します。 4つのJava Functionsはすべて、それぞれの[Functionディレクトリ](https://docs.catalyst.zoho.com/ja/cli/v1/project-directory-structure/functions-directory)に以下のファイルを含みます: * メインJava Functionファイル * `catalyst-config.json`設定ファイル * JARライブラリファイル * `.classpath`および`.project`依存関係ファイル Node.js Functionは、そのディレクトリに以下のファイルを含みます: * `index.js`メインFunctionファイル * `catalyst-config.json`設定ファイル * Nodeモジュール * `[package.json](https://docs.npmjs.com/files/package.json)`および`[package-lock.json](https://docs.npmjs.com/configuring-npm/package-lock-json.html)`依存関係ファイル 各Java FunctionのメインJavaファイルと、Node.js Functionの`index.js`ファイルにコードを追加します。 Functionの設定には任意のIDEを使用できます。 > **Note:** このセクションのコードを十分に理解するために、必ず目を通してください。セクションの最後でFunctionsのコードについて説明します。 以下のコードをコピーして、`functions/RatingProcessor`ディレクトリにある`RatingProcessor.java`に貼り付けて、ファイルを保存します。 **RatingProcessor.java** ```java import com.catalyst.Context; import com.catalyst.basic.BasicIO; import com.catalyst.basic.ZCFunction; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.logging.Logger; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import java.io.File; import java.io.FileReader; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.logging.Level; import com.zc.common.ZCProject; import com.zc.component.cache.ZCCache; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; public class RatingProcessor implements ZCFunction { private static final Logger LOGGER = Logger.getLogger(RatingProcessor.class.getName()); private static Map<String, Integer> map = new HashMap() { { put("Excellent",0); put("Very good",1); put("Average",2); put("Poor",3); put("Terrible",4); } }; @Override @SuppressWarnings("unchecked") public void runner(Context context, BasicIO basicIO) throws Exception { try { Integer topCount = 10; if(basicIO.getParameter("count") != null) { topCount = Integer.parseInt(basicIO.getParameter("count").toString()); } String travellerRating = (String) basicIO.getParameter("type"); Integer type = 0; if(travellerRating != null) { if(map.containsKey(travellerRating)) { type = map.get(travellerRating); } } String url = "https://www.zoho.com/catalyst/downloads/static/tutorial/dataset/traveller-rating.json"; ZCProject.initProject(); HttpUrl.Builder httpBuilder = HttpUrl.parse(url).newBuilder(); OkHttpClient client = new OkHttpClient().newBuilder().build(); Request.Builder requestsBuilder = new Request.Builder(); requestsBuilder.url(httpBuilder.build()); requestsBuilder.get(); Response responses = client.newCall(requestsBuilder.build()).execute(); String responsebody = responses.body().string(); JSONParser parser = new JSONParser(); JSONObject dataJSON = (JSONObject) parser.parse(responsebody); HashMap<String, Long> execellentRating = new HashMap<>(); Iterator<String> itrJson = dataJSON.keySet().iterator(); while(itrJson.hasNext()) { String museumName = itrJson.next(); List<String> ratingList = new ObjectMapper().convertValue(dataJSON.get(museumName), List.class); Long exellentRating = Long.parseLong(ratingList.get(type)); execellentRating.put(museumName, exellentRating); } execellentRating = RatingProcessor.sortByValue(execellentRating); List<String> execellentMuseum = new ArrayList<>(); itrJson = execellentRating.keySet().iterator(); Integer i= 0; while(i++ < topCount && itrJson.hasNext()) { execellentMuseum.add(itrJson.next()); } basicIO.write(new ObjectMapper().writeValueAsString(execellentMuseum)); } catch(Exception e) { LOGGER.log(Level.SEVERE,"Exception in RatingProcessor",e); basicIO.setStatus(500); } } public static HashMap<String, Long> sortByValue(HashMap<String, Long> hm) { // HashMapの要素からリストを作成 List<Map.Entry<String, Long> > list = new LinkedList<Map.Entry<String, Long> >(hm.entrySet()); // リストをソート Collections.sort(list, new Comparator<Map.Entry<String, Long> >() { public int compare(Map.Entry<String, Long> o1, Map.Entry<String, Long> o2) { return (o2.getValue()).compareTo(o1.getValue()); } }); // ソートされたリストのデータをHashMapに格納 HashMap<String, Long> temp = new LinkedHashMap<String, Long>(); for (Map.Entry<String, Long> aa : list) { temp.put(aa.getKey(), aa.getValue()); } return temp; } } ``` 以下のコードをコピーして、`functions/TravellerTypeRatingProcessor`ディレクトリにある`TravellerTypeRatingProcessor.java`に貼り付けて、ファイルを保存します。 **TravellerTypeRatingProcessor.java** ```java import java.io.File; import java.io.FileReader; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import com.catalyst.Context; import com.catalyst.basic.BasicIO; import com.catalyst.basic.ZCFunction; import com.fasterxml.jackson.databind.ObjectMapper; import com.zc.common.ZCProject; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; public class TravellerTypeRatingProcessor implements ZCFunction { private static final Logger LOGGER = Logger.getLogger(TravellerTypeRatingProcessor.class.getName()); private static Map<String, Integer> map = new HashMap() { { put("Families",0); put("Couples",1); put("Solo",2); put("Business",3); put("Friends",4); } }; @Override public void runner(Context context, BasicIO basicIO) throws Exception { try { Integer topCount = 10; String travellerType = (String) basicIO.getParameter("type"); Integer type = 0; if(travellerType != null) { if(map.containsKey(travellerType)) { type = map.get(travellerType); } } if(basicIO.getParameter("count") != null) { topCount = Integer.parseInt(basicIO.getParameter("count").toString()); } String url = "https://www.zoho.com/catalyst/downloads/static/tutorial/dataset/traveller-type-rating.json"; ZCProject.initProject(); HttpUrl.Builder httpBuilder = HttpUrl.parse(url).newBuilder(); OkHttpClient client = new OkHttpClient().newBuilder().build(); Request.Builder requestsBuilder = new Request.Builder(); requestsBuilder.url(httpBuilder.build()); requestsBuilder.get(); Response responses = client.newCall(requestsBuilder.build()).execute(); String responsebody = responses.body().string(); JSONParser parser = new JSONParser(); JSONObject dataJSON = (JSONObject) parser.parse(responsebody); HashMap<String, Long> execellentRating = new HashMap<>(); Iterator<String> itrJson = dataJSON.keySet().iterator(); while(itrJson.hasNext()) { String museumName = itrJson.next(); List<String> ratingList = new ObjectMapper().convertValue(dataJSON.get(museumName), List.class); Long rating = Long.parseLong(ratingList.get(type)); execellentRating.put(museumName, rating); } execellentRating = TravellerTypeRatingProcessor.sortByValue(execellentRating); List<String> execellentMuseum = new ArrayList<>(); itrJson = execellentRating.keySet().iterator(); Integer i= 0; while(i++ < topCount && itrJson.hasNext()) { execellentMuseum.add(itrJson.next()); } basicIO.write(new ObjectMapper().writeValueAsString(execellentMuseum)); } catch(Exception e) { LOGGER.log(Level.SEVERE,"Exception in TravellerTypeRatingProcessor",e); // このログはCatalystコンソールのLogsから確認できます basicIO.setStatus(500); } } public static HashMap<String, Long> sortByValue(HashMap<String, Long> hm) { // HashMapの要素からリストを作成 List<Map.Entry<String, Long> > list = new LinkedList<Map.Entry<String, Long> >(hm.entrySet()); // リストをソート Collections.sort(list, new Comparator<Map.Entry<String, Long> >() { public int compare(Map.Entry<String, Long> o1, Map.Entry<String, Long> o2) { return (o2.getValue()).compareTo(o1.getValue()); } }); // ソートされたリストのデータをHashMapに格納 HashMap<String, Long> temp = new LinkedHashMap<String, Long>(); for (Map.Entry<String, Long> aa : list) { temp.put(aa.getKey(), aa.getValue()); } return temp; } } ``` 以下のコードをコピーして、`functions/MergeDataSet`ディレクトリにある`MergeDataSet.java`に貼り付けて、ファイルを保存します。 **MergeDataSet.java** ```java import com.catalyst.Context; import com.catalyst.basic.BasicIO; import com.catalyst.basic.ZCFunction; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.logging.Logger; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import com.zc.common.ZCProject; import com.zc.component.cache.ZCCache; import com.zc.component.object.ZCTable; public class MergeDataSet implements ZCFunction { private static final Logger LOGGER = Logger.getLogger(MergeDataSet.class.getName()); @Override public void runner(Context context, BasicIO basicIO) throws Exception { try { Object ratingList = basicIO.getArgument("rating_list"); Object typeRatingList = basicIO.getArgument("traveller_type_rating_list"); ObjectMapper mapper = new ObjectMapper(); List<String> travellerRatingList = mapper.readValue(ratingList.toString(), mapper.getTypeFactory().constructCollectionType(List.class, String.class));; List<String> travellerTypeRatingList = mapper.readValue(typeRatingList.toString(), mapper.getTypeFactory().constructCollectionType(List.class, String.class));; List<String> finalList = new ArrayList<>(); for(int i=0 ; i< travellerTypeRatingList.size() ; i++) { if(travellerRatingList.contains(travellerTypeRatingList.get(i))) { finalList.add(travellerTypeRatingList.get(i).toString()); } } JSONObject respJson = new JSONObject(); respJson.put("museum_list", finalList); LOGGER.log(Level.INFO, "Museum Count"+finalList.size()); // このログはCatalystコンソールのLogsから確認できます basicIO.write(new ObjectMapper().writeValueAsString(respJson)); } catch(Exception e) { e.printStackTrace(); LOGGER.log(Level.SEVERE,"Exception in MergeDataSet",e); // このログはCatalystコンソールのLogsから確認できます basicIO.setStatus(500); } } } ``` 以下のコードをコピーして、`functions/Mailer`ディレクトリにある`Mailer.java`に貼り付けて、ファイルを保存します。 **Mailer.java** ```java import java.util.logging.Level; import java.util.logging.Logger; import org.json.simple.JSONObject; import com.catalyst.Context; import com.catalyst.basic.BasicIO; import com.catalyst.basic.ZCFunction; import com.zc.common.ZCProject; import com.zc.component.mail.ZCMail; import com.zc.component.mail.ZCMailContent; public class Mailer implements ZCFunction { private static final Logger LOGGER = Logger.getLogger(Mailer.class.getName()); private static final String SUBJECT = "Museum Search Results"; private static final String FROM_MAIL = "emma@zylker.com"; // 先ほど設定した送信者のメールアドレスを入力してください @Override public void runner(Context context, BasicIO basicIO) throws Exception { try { ZCProject.initProject(); Object content = basicIO.getArgument("content"); // MergeDataSet Functionから最終リストを取得 Object mailId = basicIO.getArgument("mail_id"); // 提供された入力からユーザーのメールアドレスを取得 if(content != null) { String mailContent = content.toString(); ZCMailContent mail = ZCMailContent.getInstance(); mail.setSubject(SUBJECT); mail.setFromEmail(FROM_MAIL); if(mailId != null) { mail.setToEmail(mailId.toString()); } else { basicIO.write(constructErrorMessage("mail_id not found")); basicIO.setStatus(400); return; } mail.setContent(mailContent); mail.setHtmlMode(false); ZCMail.getInstance().sendMail(mail); basicIO.setStatus(200); basicIO.write(constructSuccessMessage("Mail has been sent to "+mailId+" successfully")); } } catch(Exception e) { LOGGER.log(Level.SEVERE,"Exception in Mailer",e); // このログはCatalystコンソールのLogsから確認できます basicIO.setStatus(500); basicIO.write(constructErrorMessage(e.getMessage())); } } private JSONObject constructErrorMessage(String message) { JSONObject errorJSON = new JSONObject(); errorJSON.put("status", "failure"); errorJSON.put("message", message); return errorJSON; } private JSONObject constructSuccessMessage(String message) { JSONObject errorJSON = new JSONObject(); errorJSON.put("status", "success"); errorJSON.put("message", message); return errorJSON; } } ``` > **Note:** 先ほど設定した送信者のメールアドレスを19行目に入力してください。 #### Expressのインストール Node.js Functionのコーディングを行う前に、ディレクトリに[Express Node.js](https://expressjs.com/)の依存関係をインストールする必要があります。 ローカルマシンにExpress.jsをインストールするには、ターミナルでFunctionのディレクトリ(`functions/circuit`)に移動し、以下のコマンドを実行します: ```sh npm install express --save ``` これにより、Expressモジュールがインストールされ、依存関係が保存されます。 この情報は`package.json`ファイルにも更新されます。 次に、`index.js`ファイルをコーディングしましょう。 以下のコードをコピーして、`functions/circuit`ディレクトリにある`index.js`に貼り付けて、ファイルを保存します。 **index.js** ```javascript 'use strict'; var express = require('express'); var app = express(); var catalyst = require('zcatalyst-sdk-node'); app.use(express.json()); app.post('/triggerCircuit', (req, res) => { var CatalystApp = catalyst.initialize(req); var body = req.body; console.log(body); let execName = new Date().getTime().toString(); console.log(execName); let promiseResult = CatalystApp.circuit().execute("1028000000084051",execName, body); // コンソールで作成したCircuitのCircuit IDを入力してください promiseResult.then((functionResponse) => { console.log(functionResponse); res.status(200).send({ message: "Please check your email for the list of museums." }); }).catch(err => { console.log(err); // このログはCatalystコンソールのLogsから確認できます res.status(500).send({ message: "Please try again after sometime!" }); }) }); module.exports = app; ``` > **Note:** CatalystコンソールでCircuitを作成した後、この Functionの14行目にCircuit IDを必ず入力してください。 設定したFunctionsについて簡単に確認しましょう。 `Circuit`: * Advanced I/O `circuit` Functionには、CatalystコンソールでConfigure済みのCircuitの実行をトリガーするAPI `/triggerCircuit`が含まれています。 > **Note:** Circuitは、プロジェクトリソースをリモートコンソールにデプロイした後に設定します。 * `circuit` Functionは、クライアントアプリケーションでエンドユーザーから取得した入力データを、実行のトリガー時にCircuitに渡します。このデータは、クライアントディレクトリの`main.js`によってCircuit Functionに渡されます。 * Circuitの実行が完了すると、ユーザーの条件を満たす博物館のリストをメールで確認するよう促すメッセージがクライアントアプリケーションに表示されます。このメッセージはこのFunctionで設定されています。 `RatingProcessor`と`TravellerTypeRatingProcessor`: * `RatingProcessor` Functionは、博物館の以下の評価を[Java HashMap](https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html)に格納します:`Excellent`、`Very Good`、`Average`、`Poor`、`Terrible`。 * `TravellerTypeRatingProcessor` Functionは、博物館の以下の旅行者タイプ適合性をJava HashMapに格納します:`Families`、`Couples`、`Solo`、`Business`、`Friends`。 * 評価と旅行者タイプに加えて、ユーザーは結果に表示したい博物館の数を入力します。この値は`count`変数に格納され、両方のFunctionsで処理されます。 * Functionsは、Catalystがホストする`traveller-rating.json`または`traveller-type-rating.json`データセットをそれぞれ呼び出します。これらのデータセットには、さまざまなウェブサイトでユーザーが提供した評価や旅行者タイプの適合性のレコードが含まれています。 * ユーザーが提供した入力に基づいて、両方のFunctionsがこれらのデータセットからレコードを取得します。例えば、ユーザーが評価タイプとして`Excellent`を選択した場合、`traveller-rating.json`データセットでその評価を持つ博物館が特定されます。ユーザーが提供したcount値を超えない範囲で、`Excellent`評価が最も多い博物館が降順にソートされて取得されます。ユーザーが提供した旅行者タイプの入力に一致するレコードも、同様に`traveller-type-rating.json dataset.`から取得されます。 * 両方のFunctionsが取得したレコードはJSONオブジェクトとしてパースされ、`ObjectMapper`クラスに書き込まれます。その後、リストでソートされ、両方のFunctionsで新しいHashMapに追加されます。 `MergeDataSet`: * `MergeDataSet` Functionは、`RatingProcessor`と`TravellerTypeRatingProcessor` Functionsが取得したレコードを引数として受け取ります。 * このFunctionは両方のリストの共通部分を求め、両方のリストに存在する博物館の結果を確認します。 * 両方のリストに存在する博物館を最終リストに追加し、そのリストをJSONレスポンスとして返します。 `Mailer`: * `Mailer` Functionは、設定するCircuit内の`MergeDataSet` Functionから最終リストを取得します。これがメールの本文として設定されます。また、ユーザーが入力したメールアドレスも取得します。 * このFunctionでメールの件名と送信者アドレスを設定できます。`Mailer` Functionは、取得したコンテンツを含むメールをユーザーのメールアドレスに送信します。 Functionsディレクトリの設定が完了しました。