1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

太陽光発電の発電量をロギングしてみた。(6)Salesforceの容量不足に困ったら・・・BigObjectの活用

Last updated at Posted at 2021-01-09

【太陽光発電の発電量をロギングしてみた。目次】

Salesforce Developer Editionの限界

(4)Salesforseでリアルタイム監視で説明したが、Salesforce Developer Editionは、利用可能なデータストレージが5MByteしかない。
はじめ、電流値のロギングを10秒周期でアップロードしていたが、1日半で制限に引っかかり、アップロード不能になってしまった。
最も手っ取り早い対策方法は、アップロード周期を長めにとることである。

しかし、この制限を意識せずに利用する方法が存在する。
それは、BigObjectを活用することである。

BigObjectとは?

主に、履歴やログを残すのに用いられるオブジェクトである。
Developer Editionでは100万レコードまで保持することが可能である。
BigObjectが通常のオブジェクトと異なるところは、

・ レポートやダッシュボードなど通常の機能で使用できない。
・ 通常のカスタムオブジェクトはAPIアクセス名に「__c」がついたが、BigObjectは「__b」
・ リレーショナルデータベースでなく分散型データベース
・ 非トランザクションデータベース

詳細は以下を参照

【参照】
Salesforce および Lightning プラットフォームのオブジェクトリファレンス

どう活用できるの?

まず、手始めに、作成したカスタムオブジェクトと同等の項目定義をもつBigObjectを作成しておき、容量オーバーになる前にカスタムオブジェクトのデータをBigObjectにバックアップしてから削除することができる。

BigObjectに格納しても標準のレポート機能で使用できないのでグラフ表示できない!と思われるかもしれないが、ちょっと頑張れば、この問題をクリアする方法がある。
自分で作成するVisualforceページからはBigObjectにアクセス可能である。

BigObjectの作成

「設定」-「管理」-「データ」-「BigObject」を選択する。

image.png

「New」ボタンをクリックする。

image.png

表示ラベル・オブジェクト名を指定して「保存」する。

SF10.png

カスタム項目&リレーションで「新規」をクリック。

image.png

データ型を選択して「次へ」

image.png

この辺はカスタムオブジェクト作成時と同じである。
カスタムオブジェクトと同様に項目を作成すること。

ただし、数式項目は作成できないので注意する。

カスタムオブジェクトからBigObjectへのデータバックアップ

ここでは、開発者コンソールを利用して作業を行う。
開発者コンソールは、「設定」同様、画面右上のギアボタンのメニューから起動できる。

image.png

「開発者コンソール」を選択すると、別ウィンドウで開発者コンソールが起動する。

開発者コンソールでは、SOQL (Salesforceで使用するSQL)を実行できる。

SF11.png

画面下のパネルの「Query Editor」にSOQLを入力し、一番下のExecuteをクリックする。すると、真ん中のパネルに実行結果が表示される。
これで、現在保持しているデータを確認できる。

では、データをカスタムオブジェクトから引き出して、BigObjectに格納するにはどうしたらよいか?
これは、普通にSOQLを発行するだけでは不可能である。
これには、Apexを使用する。

上部メニューから「Debug」-「Open Execute Anonymous Window」をクリック。
image.png

Enter Apex Codeウィンドウが起動するので、実行したいApexコードを入力する。

image.png

サンプルコード

List <GeneratorLog__c> lst =
 [SELECT Id,Name,Current__c,Voltage__c,Temperature__c FROM GeneratorLog__c WHERE MeasDate__c= TODAY AND hour__c=12] ;
 
if (lst.size() > 0 ) {
    
    for(GeneratorLog__c data : lst)
    {
        GeneratorLogStack__b entity = new GeneratorLogStack__b(
            No__c = data.Name,
            Date__c = data.Name,
            Current__c = data.Current__c,
            Voltage__c = data.Voltage__c,
            Temperature__c = data.Temperature__c
        );
        Database.insertImmediate(entity);
    }
    
 delete lst;
 system.debug('★' + lst.size()+ '件 削除しました★');
} else {
 system.debug('★該当データなし★');
}

入力したソースは、Executeボタンクリックで実行される。
ただし、一回の実行時間に制限がある。(10秒くらい)
大量にデータをコピー・削除しようとすると、途中で切られてしまうので、Where条件でデータを分割しながらデータ移行するとよい。

Visualforceページの作成

バックアップしたデータも、やはりグラフ表示できると嬉しい。
これにはVisualforceページを使用する。

Visualforceページの作成は以下の手順で行う。

「設定」-「プラットフォームツール」-「カスタムコード」-「Visualforceページ」を選択。

SF12.png

「新規」ボタンをクリック。
表示ラベルと名前を入力する。

image.png

デフォルトで数行コードが書かれており、そのまま保存してプレビューすると、以下のページが表示されるようになる。

image.png

ここで、「私の個人情報」-「高度なユーザの詳細」で、「開発モード」のチェックがONになっていると、ページ左下に「X」ボタンが出現する。
これをクリックすると、コードエディタが下部に表示され、出力を確認しながらコードを書けるようになっている。

次に、コードの実装に移るが、Visualforceの実装の前に、VisualforceページコントローラをApexで作成する必要がある。

Apexクラスの作成は、
「設定」-「プラットフォームツール」-「カスタムコード」-「Apexクラス」を選択。「新規」ボタンを押し、ここでは「ChartController」という名前でクラスを作成する。

public class ChartController {

    static String searchText;
    
    public String getSearchText() {
        return searchText;
    }
 
    public void setSearchText(String s) {
        searchText = s;
    }
    List<Data> results;
    
    // Return a list of data points for a chart
    public List<Data> getData() {
        return ChartController.getChartData();
    }
    
    // Make the chart data available via JavaScript remoting
    @RemoteAction
    public static List<Data> getRemoteData() 
    {
        return ChartController.getChartData();
    }

    public static Decimal Average(List<Decimal> numlist)
    {
        Decimal ret=0;
        Decimal sum=0;
        for(Decimal d : numlist)
        {
            sum += d;
        }
        if(numlist.size()>0)
        {
            ret = sum/numlist.size();
        }
        return ret;
    }
    
    public List<Data> getResults() {
        return results;
    }
     
    public PageReference doSearch() {
        results = getChartData();
        return null;
    }
    
    // The actual chart data; needs to be static to be
    // called by a @RemoteAction method
    public static List<Data> getChartData() {
    
        List<Data> data = new List<Data>();
        List<List<Decimal>> currentPH = new List<List<Decimal>>();
        List<List<Decimal>> voltagePH = new List<List<Decimal>>();
        List<List<Decimal>> tempPH = new List<List<Decimal>>();
        
        for(Integer i=0;i<18;i++)
        {
            currentPH.add(new List<Decimal>());
            voltagePH.add(new List<Decimal>());
            tempPH.add(new List<Decimal>());
        }
        
        Date d = Date.newInstance(Integer.valueOf(searchText.left(4)), Integer.valueOf(searchText.mid(5, 2)), Integer.valueOf(searchText.mid(8,2)));
        String dateP = String.valueOf(d.addDays(-1));
        String dateL = String.valueOf(d.addDays(1));
        List<GeneratorLogStack__b> lst = [SELECT No__c, Date__c, Current__c, Voltage__c, Temperature__c FROM GeneratorLogStack__b WHERE No__c < :dateL AND No__c > :dateP];
        
        for (Integer i=0;i<lst.size();i++)
        {
            GeneratorLogStack__b entity=lst[i];
            Integer hour = Integer.valueOf(entity.No__c.mid(11,2));
            currentPH[hour].add(entity.Current__c);
            voltagePH[hour].add(entity.Voltage__c);
            tempPH[hour].add(entity.Temperature__c);
        }
        for(Integer i=7;i<18;i++)
        {
            data.add(new Data(i.format(), Average(currentPH[i]), Average(voltagePH[i]), Average(tempPH[i])));

        }
        return data;
    }
    
    
    // Wrapper class
    public class Data {
        public String name { get; set; }
        public Decimal data1 { get; set; }
        public Decimal data2 { get; set; }
        public Decimal data3 { get; set; }
        public Data(String name, Decimal data1, Decimal data2, Decimal data3) {
            this.name = name;
            this.data1 = data1;
            this.data2 = data2;
            this.data3 = data3;
        }
    }
}

【参照】
Visualforce Charting を使用した複雑なグラフの作成

Apexクラスを保存したら、再びVisualforceの編集を行う。

<apex:page controller="ChartController">
    <apex:form >
        <apex:pageBlock mode="edit" id="block">
            <apex:pageBlockSection >
                <apex:pageBlockSectionItem >
                    <apex:outputLabel for="searchText">Search Date</apex:outputLabel>
                    <apex:panelGroup >
                        <apex:inputText id="searchText" value="{!searchText}"/>
                        <apex:commandButton value="Go" action="{!doSearch}" rerender="block" status="status"/>
                    </apex:panelGroup>
                </apex:pageBlockSectionItem>
            </apex:pageBlockSection>
            <apex:actionStatus id="status" startText="requesting..."/>
            <apex:pageBlockSection title="Results" id="results" >
                <apex:chart height="400" width="700" data="{!results}">
                    <apex:legend position="right"/>
                    <apex:axis type="Numeric" position="left" fields="data1"
                        title="Currenct(A)" grid="true"/>
                    <apex:axis type="Category" position="bottom" fields="name"
                        title="Hour">
                        <apex:chartLabel rotate="315"/>
                    </apex:axis>
                    <apex:lineSeries title="{!searchText}" axis="left" xField="name" yField="data1"
                        fill="true" markerType="cross" markerSize="4" markerFill="#FF0000"/>
                </apex:chart>
                <apex:chart height="400" width="700" data="{!results}">
                    <apex:legend position="right"/>
                    <apex:axis type="Numeric" position="left" fields="data2"
                        title="Voltage(V)"/>
                    <apex:axis type="Category" position="bottom" fields="name"
                        title="Hour">
                        <apex:chartLabel rotate="315"/>
                    </apex:axis>
                    <apex:lineSeries title="{!searchText}" axis="left" xField="name" yField="data2"
                        markerType="circle" markerSize="4" markerFill="#8E35EF"/>
                </apex:chart>
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>
</apex:page>

このコードを保存して実行すると、以下のような画面になる。
テキストボックスに年月日を「yyyy-MM-dd」形式で指定すると、該当する日付の電流/電圧グラフが表示される。

image.png

あとは、このVisualforceページ用のタブを作成するだけである。

「設定」-「プラットフォームツール」-「ユーザインターフェース」-「タブ」を開き、Visualforceページタブを新規作成する。
作成したタブを、任意のアプリケーションに追加すると画面から簡単にアクセスできるようになる。

もう少しUIを工夫すれば、標準レポートを使用せず、最初からすべてのデータをBigObjectに投入し、Visualforceページで監視することも可能だ。

【太陽光発電の発電量をロギングしてみた。目次】

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?