1. データ管理について
リレーショナルデータベース(RDB)などに代表されるデータの構造定義や永続化を実現する仕組みとして、 iPLAssではEntityメタデータを利用します。 RDBにおけるテーブルはEntityとして定義し、テーブルのカラムはPropertyとして定義します。
Entityには以下の機能・特徴があります。
-
動的な定義
Entityは管理画面上から動的に作成することができます。 RDBのように物理的にテーブルを追加・修正する必要はありません。 またEntityに定義可能なPropertyにはタイプ(StringやInteger、Binaryなど)ごとに 特化したProperty型があらかじめ用意されています。 格納したいデータタイプに合わせてProperty型を選択していきます。 -
データ操作画面の自動生成(Generic Entity Manager)
Entityを定義するだけで、汎用的な検索画面、登録・編集画面が実行可能になります。 汎用画面は、表示項目や表示レイアウトなど、独自にカスタマイズすることもできます。 またカレンダービュー、ツリービューなどいくつかの表示形式を標準で提供しています。
詳細はGEM(Generic Entity Manager)を参照してください。 -
データ検証
Propertyごとに必須チェックやLengthチェックなどのValidatorを設定することができます。 -
EventListener
EntityのCRUD操作(登録、参照、更新、削除など)時の前後に独自処理を組み込むことができます。 -
データのバージョン管理
Entityの1レコードに対して、複数のバージョンを保持することができます。 バージョン管理を利用することで、修正履歴を保持できたり、先日付データを事前に登録することが可能になります。 -
Entityの権限制御
EntityのCRUD操作(登録、参照、更新、削除など)に対する権限をロールを利用して制御することができます。
詳細は認可を参照してください。 -
クエリ言語(EQL)
データ操作はiPLAss独自のEQLというSQLライクなクエリ言語を利用します。 Entityデータの永続化にはバックエンドでRDBを利用しますが、 開発者はバックエンドのRDB差異を意識する必要はほとんどありません。
詳細はEQLリファレンスを参照してください。 -
WebApi操作
EntityのCRUD操作(登録、参照、更新、削除など)を実行するWebApiを標準で提供しています。
詳細はEntityCRUD APIを参照してください。 -
全文検索
Entityデータに対して、全文検索エンジンを利用したIndexの生成、検索機能を標準でサポートしています。
詳細は全文検索を参照してください。 -
データ監査ログ
EntityのCRUD操作(登録、参照、更新、削除など)に対するログを記録することができます。 記録されたログはデータ操作画面上で表示したり、管理コンソール上で参照することができます。 -
データ暗号化
Entityのデータ内容をデータベースに保存する際に暗号化することができます。 データベースの暗号化オプションを利用可能な場合は、そちらを利用することを推奨しますが、 データベースの暗号化オプションの利用が難しい場合の次善のソリューションとして利用可能です。
2. Entity
2.1. Entityの作成
Entityアイコンを右クリックして「Entityを作成する」を選択してください。
階層化(フォルダのようにグループ化)する場合はドット(.)区切りで指定してください。 他のメタデータは基本的にスラッシュ(/)で階層化しますが、Entityは特別です。 |
Entityを作成したタイミングで、メニューアイテムが作成されます。
またテナントに標準で作成されている DEFAULT メニュー定義がある場合は、
最後にアイテムが追加されます。
|
2.2. 共通Property
Entityにはあらかじめ標準PropertyとシステムPropertyが定義されています。
あらかじめ定義されているPropertyは変更や削除することはできません。 共通のPropertyとして利用されている名前は予約語です。Entity内で同じ名前のPropertyを定義することはできません。 |
標準Property
レコードのキーに該当するIDやレコードの内容を表すPropertyが定義されています。
名前 | 表示名 | データ型 | 内容 |
---|---|---|---|
オブジェクトID |
String |
レコードを一意に特定するID。変更不可。 |
|
名前 |
String |
レコードを表すラベル。必須項目。値はユニークである必要はありません。 |
|
説明 |
String |
レコードの説明。任意項目。 |
オブジェクトID (oid)
Entityデータは1レコード単位に oid
という一意のKEY値を保持します。
標準の動作として、oid
はEntityデータの登録時に自動的に採番されます。
更新処理で変更することはできません。
後述するEntityどうしの参照定義(Reference Property)においても、
この oid
で参照関係を保持します(正確には oid
+ version
です)。

標準で自動採番される oid
値は、Entity単位で一意となる値です。
テナント単位で一意な値ではないので、 oid
からEntityを特定することはできません。
名前 (name)
name
はレコードに対するラベルを想定しています。
name
は必須項目ですが値の変更は可能です。また値として一意である必要もありません。
説明 (description)
description
はレコードに対する説明を想定しています。
description
はString型の任意項目なので、利用可否も含め自由に利用してください。
システムProperty
データのバージョン制御のためのPropertyや、データ操作時の情報を保持するPropertyが定義されています。 システムPropertyは自由に値を設定することはできません。データ操作時に自動で制御されます。
名前 | 表示名 | データ型 | 内容 |
---|---|---|---|
version |
バージョン |
Integer |
データのバージョン管理 で利用。管理しない場合は0。 |
state |
ステータス |
Select |
バージョン管理用。 |
startDate |
有効開始日 |
DateTime |
バージョン管理用。 |
endDate |
有効終了日 |
DateTime |
バージョン管理用。 |
createDate |
作成日 |
DateTime |
データ作成日時。 |
updateDate |
更新日 |
DateTime |
データ更新日時。 |
createBy |
作成者 |
String |
データ作成者。作成者に該当する |
updateBy |
更新者 |
String |
データ更新者。更新者に該当する |
lockedBy |
ロックユーザ |
String |
データロック機能用。ロック者に該当する |
システムPropertyは制御用としてiPLAss内部で制御されるため、 各アプリケーションで独自の用途として値を格納したりしないでください。 バージョンアップなどで増減したり、格納される値が変更される可能性があります。
startDate
や endDate
についても、「ユーザ」「おしらせ情報」Entityなどで一部利用していますが、
Entityの バージョン管理設定 により利用される可能性があるため、基本的には利用できません。
2.3. 設定
Entityに対して、保存したいデータ項目に合わせたPropertyを追加していきます。
Entityに対するより高度な設定については 高度な設定 で説明します。
Propertyの作成
Propertyを作る際は、格納する値の型に特化したデータ型の選択や、必須項目や長さなどの制約条件の設定を行います。
Propertyを追加する場合は Add
ボタン、編集する場合は対象のPropertyレコードをダブルクリック、
削除する場合は対象のPropertyを選択(ShiftやCtrlで複数可)して Remove
ボタンをクリックします。
またPropertyの順番を並び替える場合はDrag&Dropで並び替えてください。
Propertyの設定
Propertyは次の項目を設定可能です。 また指定したPropertyのデータ型によって、設定する項目が変更されます (一部データ型により変更できない項目があります)。
設定項目 | 設定内容 |
---|---|
Name |
物理名を指定します。英数字のみ指定可能です。 |
Display Name |
表示名を指定します。 |
データ型を指定します。 |
|
多重度を指定します。 |
|
Required |
必須項目かを指定します。 |
CanEdit |
値を変更できるかを指定します。 |
インデックスを指定します。 |
|
暗号化有無、および形式を指定します。 |
|
検証ロジックを指定します。 |
データ型の指定
提供されているPropertyのデータ型です。基本的な型とiPLAssに特化した特殊な型があります。
型 | 説明 | Java型 |
---|---|---|
String |
文字列型です。 |
String |
Boolean |
真・偽を表す型です。 |
Boolean |
Integer |
整数を表す数値型です。 |
|
Float |
小数を表す数値型です。 |
Double |
Decimal |
正確な小数計算を扱う数値型です。 |
BigDecimal |
DateTime |
日付と時間を表す型です。 |
java.sql.Timestamp |
Date |
日付を表す型です。 |
java.sql.Date |
Time |
時間を表す型です。 |
java.sql.Time |
型 | 説明 | Java型 |
---|---|---|
選択値として「値とラベル」のセットを定義することができる型です。 |
org.iplass.mtp.entity.SelectValue |
|
自動採番値を扱う型です。 |
String |
|
式を設定することができる型です。 |
String |
|
バイナリデータを扱う型です。(BLOB型) |
org.iplass.mtp.entity.BinaryReference |
|
String型では入りきらない文字列を扱う型です。(BLOB型) |
String |
|
各エンティティを関連付ける事ができる型です。 |
org.iplass.mtp.entity.Entity |
Java型はCommandやUtilityClass、TemplateなどでEntityデータを扱う際のデータ型です。
それぞれのデータ型の詳細は、データ型 を参照してください。
多重度について
Entityには1つのPropertyに対して複数の値を保持することが可能となっています(配列イメージ)。
oid | name | col1(multiple=5) | ref1(multiple=*) |
---|---|---|---|
1 |
data1 |
[a,b,c,d,e] |
[{oid=1,ver=0},{oid=2,ver=0},{oid=3,ver=0}] |
2 |
data2 |
[a,b,c] |
[] |
3 |
data3 |
[] |
[{oid=1,ver=0},{oid=2,ver=0}] |
-
Reference
型については、無制限を表す「*」を指定できます。 -
Reference
型以外のPropertyは数値のみ指定できます。
Reference
型以外で多数の多重度を持たせたい場合は、パフォーマンスを考慮して、
別Entityを定義して Reference
型で参照するようにするか、
独自の Storage Space を利用することを検討してください。
2.4. 高度な設定
Entityに対して提供されているその他の機能について説明します。
設定項目 | 設定内容 |
---|---|
|
|
Entityデータのバージョン管理方式を指定します。 |
|
Entityデータの格納先を指定します。 |
|
EntityデータのCRUD操作に対するログを記録するかを指定します。 |
|
全文検索機能用のINDEXを作成するかを指定します。 |
|
Entityの検索結果をキャッシュするかを指定します。 |
|
CommandなどでEntity操作を行う際に、Javaで実装されたEntityクラスを利用する場合に指定します。 |
|
EntityのEventListenerを指定します。 |
|
Entityデータの国際化対応を指定します。 |
共通Propertyの変更
oid
と name
については他のPropertyを指定することで代用することができます。
oid Propertyの変更
外部システムからのデータ取り込みや、IDとしてユーザにわかりやすい値にしたい場合など、
oid
として利用するPropertyを変更することが可能です。
Admin Consoleで oid
を指定する場合は、「OID」列で指定してください。

以下の属性のPropertyのみ oid
として指定することが可能です。
-
型が 基本型 または AutoNumber である
-
必須項目である
-
変更不可である
-
多重度が1である
複数のPropertyを指定することが可能です。
この場合、 oid
に格納される値は、選択したPropertyを上から順番にハイフン「-」で
結合した値になります。
既に登録済みのEntityデータが存在する状態で oid
Propertyを変更した場合、
登録済みのデータは自動的には変更されません。
このような場合は、Entityデータのエクスポート/インポートなどによりデータを手動で変更する必要があります。
name Propertyの変更
oid
同様、 name
も対象とするPropertyを変更することが可能です。
Admin Consoleで変更する場合は、「Name」列で指定してください。
以下の属性のPropertyのみ name
として指定することが可能です。
-
型が 基本型 、 AutoNumber 、 Select のいずれかである
-
必須項目である
-
多重度が1である
oid
と異なり、複数のPropertyを指定することはできません。
name
を指定した場合には、以下の点について考慮する必要があります。
-
登録時の動作
name
Propertyを独自に設定した場合、Entityデータの更新時にname
に同じ値が設定されます(name
Propertyがなくなるわけではありません)。 例えば、name
Propertyと、独自に指定したPropertyそれぞれに値を設定して更新した場合、name
に設定された値は上書きされます。 -
汎用画面(GEM)のカスタマイズが必要
汎用画面では、標準でname
とdescription
Propertyが検索・詳細画面上に表示されます。name
Propertyを独自に設定した場合は、name
を削除し独自Propertyを追加するなど、汎用画面のレイアウト調整が必要です。
既に登録済みのEntityデータが存在する状態で name
Propertyを変更した場合、
登録済みのデータは自動的には変更されません。
例えば、必須ではない項目を必須に変更して name
に指定した場合も、
登録済のデータは値が設定されていない可能性がある状態になってしまいます。このようなデータは最初の更新時にエラーになります。
この場合は、Entityデータのエクスポート/インポートなどにより登録済みデータを手動でメンテナンスする必要があります。
作成したいEntityに name
に該当するPropertyがない場合は、 AutoNumber 型のPropertyを作成して、それを name
として指定してください。
データのバージョン管理
Entityの1レコードに対して、複数のバージョンを保持することができます。 バージョン管理を利用することで、修正履歴を保持できたり、先日付データを事前に登録することが可能になります。
管理方式には以下の種類があります。
タイプ | 説明 |
---|---|
NONE |
バージョンデータを保持しません。データに対する最新の状態のみ保持されます。 |
NUMBER BASE |
共通Propertyの |
TIME BASE |
共通Propertyの |
共通Propertyの version
を複数保持することが可能になります。
検索処理で有効なデータは version
が最大のものになります。

version は排他制御のためのものではありません。排他制御は updateDate でチェックしています。
|
共通Propertyの startDate
、 endDate
(有効期間)を複数保持することが可能になります。
データを更新する際に有効期間を指定します。
検索処理で有効なデータは システム日時で決定されます。

データ更新時に有効期間が未指定の場合は、自動的に「システム日時」~「2099/12/31 00:00:00」が設定されます。
また TIME BASE
の場合も version
はカウントアップされます。
上の例のように有効期間が重ならないようにデータを更新した場合は問題ないのですが、 例えば有効期間が「2018/1/1」から「2018/12/31」のデータに対して、「2018/6/1」から別の値に変更したい場合は、 別バージョンのデータ「2018/6/1」~「2018/12/31」を作成すると有効期間がかぶります。

システム日時に対して有効なデータ期間が複数存在する場合は、 version
が大きい方が有効なデータとなります。
もしデータとして重複を避けたい場合は、登録済のデータの有効終了日を新しい有効開始日の前(「2018/1/1」~「2018/5/31」)に修正してください。

新しいバージョンのデータを作成する場合は、明示的に更新する必要があります。 普通に更新した場合は新しいバージョンデータは作成されず、対象バージョンのデータが更新されます。
汎用画面からデータを登録する場合は、詳細画面に 新しいバージョンとして更新
というボタンが表示されるので、
そこから更新を行います。
Commandなど独自で更新処理を実装する場合は UpdateOption
で設定します。
import org.iplass.mtp.entity.EntityValidationException;
import org.iplass.mtp.entity.UpdateOption;
import org.iplass.mtp.entity.TargetVersion;
EntityManager em = ManagerLocator.manager(EntityManager.class);
try {
//別バージョンで更新する場合、UpdateOptionに対して、
//TargetVersion.NEWを指定すると新しいバージョンとして保存される
//通常のupdate処理は「TargetVersion.CURRENT_VALID」(有効バージョン)
UpdateOption option = new UpdateOption();
option.setTargetVersion(TargetVersion.NEW);
em.update(entity, option);
} catch (EntityValidationException e) {
}
Entity間の連携を定義するためのReference型のPropertyが参照する参照先のバージョンは、 ReferencePropertyで指定した「バージョン管理」設定によって決定されます。
バージョン管理を行う場合、 Unique Index
が指定されたPropertyは変更不可になります。
Entity定義の保存時に、 Unique Index
が指定されているPropertyは canEdit = false
として保存されます。
Storage Spaceの変更
全てのEntityのデータは、標準の設定ではバックエンドのRDB上で1つの物理テーブルに格納されます。
例えば、
-
一部のデータを暗号化したいため当該Entityを格納するテーブルのテーブルスペースを分けたい
-
あるEntityは大量件数が想定されるため、他のデータとは物理的に別テーブルで管理し、他のEntityへのパフォーマンス面での悪影響を抑えたい
といった要件を実現すため、Entityデータを格納する領域をEntity単位で指定することが可能です。
この領域のことをiPLAssでは Storage Space
と呼称します。
ただしこの機能を利用するには、通常意識しないバックエンドDB上に物理テーブルを作成し、service-configにStorageSpace定義が必要となります。
詳細は Storage Space を参照してください。
データ操作ログの記録
EntityデータのCRUD操作に対するログを記録することができます。
記録されたログは、汎用画面の操作ログSectionで表示することが可能です。 詳細は 操作ログセクションを参照してください。
また AuditLogManager
を利用することでプログラム上で取得することが可能です。
/** 注意:以下はGroovy形式で書いています。 */
import org.iplass.mtp.ManagerLocator;
import org.iplass.mtp.entity.auditlog.AuditLog;
import org.iplass.mtp.entity.auditlog.AuditLogManager;
//import org.iplass.mtp.entity.auditlog.AuditLog.Action;
AuditLogManager alm = ManagerLocator.manager(AuditLogManager.class);
String entityName = "samples.Sample";
String oid = "00001";
//ログは件数が多くなることが想定されるため、limit(-1などは不可)、offsetの指定が必要です
int limit = 100;
int offset = 0;
//ログの取得
List<AuditLog> auditLogs = alm.getAuditLog(entityName, oid, limit, offset);
println("audit log size =" + auditLogs.size());
auditLogs.each{auditLog ->
println("log id =" + auditLog.getLogId());
println("action =" + auditLog.getAction()); //操作Action(AuditLog.Action)
println("user =" + auditLog.getUserId()) //操作ユーザ(oid)
println("property =" + auditLog.getPropertyName()) //プロパティ
println("oldValue =" + auditLog.getOldValue()) //更新前の値
println("newValue =" + auditLog.getNewValue()) //更新後の値
//他の値はAuditLogのJavaDocを参照してください。
};
/* java形式
auditLogs.forEach(auditLog -> {
System.out.println("log id =" + auditLog.getLogId());
System.out.println("action =" + auditLog.getAction());
・・・・・
});
*/
操作ユーザに格納されている値は ユーザID
のため、名称が必要な場合は検索する必要があります。
またReferencePropertyに対する値も oid
のため、参照先の名前などが必要な場合は検索する必要があります。
Query結果のキャッシュ
検索時のQueryに対する検索結果をキャッシュすることが可能です。 実行されたQueryと同じ条件のQueryがキャッシュに存在すれば、実際の検索を実行せずにキャッシュの結果を返します。 キャッシュデータは、対象のEntityデータが1件でも更新されたタイミングでクリアされます。
Mapping Classの利用
Entityの検索処理として利用する EntityManager
のload処理やQuery(EQL)を使ったsearchEntity処理の結果として、
標準では Entity
インターフェースを実装した GenericEntity
クラスが返ってきます。
org.iplass.mtp.entity.Entity
org.iplass.mtp.entity.GenericEntity
この GenericEntity
クラスには共通Property項目に対するAccessorメソッドは提供されていますが、
各Entityで個別に追加したPropertyに対しては、
getValue("プロパティ名")
、 setValue("プロパティ名", 値)
としてデータを操作する必要があります。
そこで Entity
インターフェースを実装したJavaクラスを作成し、各Entityのプロパティに対応したAccessorメソッドを定義できるようにするのが
このMapping Classです。Javaクラスの名前を指定した場合、loadやsearchEntity処理の結果として、指定したJavaクラスのインスタンスが返ります。
AdminConsoleの Create Java Class
を実行することで、
保存されているEntity定義に対応するJavaクラス( GenericEntity
の継承クラス)のコードを生成、ダウンロードできます。
MappingするJavaクラスは、クラスパス上に配置する必要があります。Paas的な環境では利用できません。 |
EventListener
Entityに対する操作時に独自の処理を実行したい場合、操作イベントに対してListenerを設定することができます。 ListenerはJavaClassまたはGroovyScriptとして実装することができます。
Entityのイベント
イベントは EntityManager
を経由したEntity操作時に発生します。
汎用画面でのEntity操作時にも、内部的に EntityManager
を利用しているためイベントが発生します。
以下に EntityManager
のメソッドとイベントの関連を示します。
EntityManager#method | イベント | 戻り値 | 説明 |
---|---|---|---|
load |
onLoad |
void |
ロード処理。 |
searchEntity |
onLoad |
void |
検索処理(Entity形式)。1件ごとに呼び出される |
validate |
beforeValidate |
void |
検証処理。 |
insert |
beforeValidate |
void |
登録処理。 |
update |
beforeValidate |
void |
更新処理。 |
delete |
beforeDelete |
boolean |
削除処理。 |
purge |
afterPurge |
void |
ごみ箱から、削除処理。 |
restore |
afterRestore |
void |
ごみ箱から、復活処理。 |
search 、 updateAll 、 deleteAll 時はイベントは発生しません。イベントの戻り値として boolean を返すものは、 false を返すと後続の処理を実行しません。update 、 delete 時など更新前のEntityが存在する状態で、各通知メソッドが呼び出される際の引き渡されるentityインスタンスは、
EntityManagerから各更新メソッド呼び出し時のEntityインスタンスがそのまま引き渡されたものです。
そのため、oid以外のプロパティ項目を保持していない場合もあることご注意ください。
|
Javaクラスによる実装
JavaクラスとしてEventListenerを実装する場合は、 EntityEventListener
インターフェースを実装したクラスか、
空実装されている EntityEventAdapter
クラスの継承クラスを作成します。
org.iplass.mtp.entity.EntityEventListener
org.iplass.mtp.entity.EntityEventAdapter
設定項目 | 設定内容 |
---|---|
class name |
実装したクラスを指定します。 |
mapped by reference info is unnecessary for listener |
|
public class UserEntityEventListener extends EntityEventAdapter {
/**
* FIRST_NAME、LAST_NAMEからNameを設定する
*/
@Override
public void beforeValidate(Entity entity, EntityEventContext context) {
String firstName = entity.getValue(User.FIRST_NAME);
String lastName = entity.getValue(User.LAST_NAME);
String name = firstName + lastName;
entity.setName(name); //ユーザ名をセットする
}
/**
* 更新対象項目として名前が含まれていない場合、名前を追加する
* (validate内で手動で変更しているので)
*/
@Override
public boolean beforeUpdate(Entity entity, EntityEventContext context) {
//コンテキストから更新Optionを取得
UpdateOption uo = (UpdateOption) context.getAttribute(EntityEventContext.UPDATE_OPTION);
//更新対象項目として名前が含まれていない場合
if (!uo.getUpdateProperties().contains(Entity.NAME)) {
//コンテキストから変更前のEntityを取得
Entity before = (Entity)context.getAttribute(EntityEventContext.BEFORE_UPDATE_ENTITY);
//名前の変更チェック
if (!before.getName().equals(entity.getName())) {
uo.getUpdateProperties().add(Entity.NAME); //異なる場合は更新項目として追加する
}
}
return true;
}
}
引数で渡されるEntityEventContextについては、EntityEventContext を参照してください。
Scriptによる実装
Script(GrovyScript)でEventListenerを実装する場合は、scriptとして2種類の定義方法があります。
-
Javaと同様に、EntityEventListenerをimplementsしたクラスを記述。
-
対象のEventを指定し、実行されるScriptを記述。
設定項目 | 設定内容 |
---|---|
script |
実行するScriptを指定します。Javaと同様の形式で記述する場合は、 Javaクラスによる実装 を参照してください。 クラス形式を指定した場合は、選択されたEventは無視されます。 |
events |
実行するイベントをしています。 複数指定した場合は、各イベントで同じスクリプトが実行されます。 |
mapped by reference info is unnecessary for listener |
|
利用可能なバインド変数は以下のものです。
バインド変数 | 設定される値 |
---|---|
entity |
対象のEntityデータ。 |
context |
EntityEventContext |
event |
発生したイベント種別。
|
user |
ユーザ情報。 |
date |
システム日時。 |
event
には発生したイベントのタイプが設定されています。
Script形式の場合、1つのListenerで複数のEventに対する処理を実装できるので、Eventごとに処理を分けたい場合の判断として利用します。
このような場合、EventごとにそれぞれListener定義することもできます。
import org.iplass.mtp.entity.definition.listeners.EventType;
if (event == EventType.BEFORE_VALIDATE) {
・・・・・
} else if (event == EventType.BEFORE_UPDATE) {
・・・・・
return true;
}
boolean
の戻り値が必要なイベントにに対して、戻り値を返していない場合は true
として制御します。
EntityEventContext
更新系のイベントに対しては EntityEventContext
という引数で、対象Entityに関する更新情報が渡されます。
org.iplass.mtp.entity.EntityEventContext
EntityEventContextには以下の情報が格納されています。
KEY | 対象Event | 値 |
---|---|---|
VALIDATE_PROPERTIES |
beforeValidate |
バリデーション対象のProperty名のList(List<String>)。
|
UPDATE_OPTION |
update時 |
updateの引数で渡されたUpdateOption。 |
BEFORE_UPDATE_ENTITY |
beforeUpdate |
更新前のEntity(load) |
DELETE_OPTION |
delete時 |
deleteの引数で渡されたDeleteOption |
KEYはEntityEventContextの変数名として定義されています。
EntityEventContextはMap形式で値を保持することができるので、
イベント間で独自の値も受け渡すことができます。
EntityEventContext#getAttribute(KEY)
、 EntityEventContext#setAttribute(KEY, value)
で値を取得、設定してください。
EntityEventContextはEntityManagerのメソッド呼び出しの単位でインスタンスが生成されます。
Entityに対して複数イベントを登録している場合は、複数イベント間で共有されます。
ただし update
時に発生する beforeValidate
イベントは、
beforeValidate
内のみで共有されます(後続の beforeUpdate
以降は別インスタンス)。
EntityManager#update(・・・・・)
////beforeValidateイベント実行
EntityEventContext eeContext = new EntityEventContext();
for (EntityEventListener listener: listeners) {
listener.beforeValidate(entity, eeContext);
}
//validate処理実行
//handleBeforeUpdateイベント実行
//検証時のEntityEventContextは引き継がない
EntityEventContext eeContext2 = new EntityEventContext();
for (EntityEventListener listener: listeners) {
if (!listener.handleBeforeUpdate(entity, eeContext2)) {
return;
}
}
//実際のupdate処理実行
//handleAfterUpdateイベント実行
for (EntityEventListener listener: listeners) {
listener.handleAfterUpdate(entity, eeContext2);
}
update処理時にはEntityEventContextに更新前のEntity情報がloadされてセットされます。 このload時に被参照Propertyを取得しないかを設定します。
true
の場合、更新前Entityのload処理で被参照Propertyを除外します。
(load時のLoadOptionを withMappedByReference=false
にして処理します)
被参照Propertyは更新対象のPropertyではないため、Listener内部の処理で参照する必要がないのであれば、除外することで処理を高速化できます。
データの多言語化
Entityデータ自体に対する多言語設定が行えます。多言語設定は Data Localization
で指定します。
詳細については、 データの多言語化を参照してください。
3. Entity Property
データ型、Validatorについての詳細を記載します。
インデックス指定、データの暗号化については、 高度な設定で説明します。
3.1. データ型
データ型を一覧で参照したい場合は、 データ型の指定 を参照してください。
基本型の注意点
String型の文字数制約
String型はバックエンドとして利用するRDBの定義によって、格納できる最大文字数が制限されます。
標準の設定の場合、Oracleは varchar2(4000)
、MySQLは TEXT
です。
また文字コードは UTF-8
なので、全角2000文字でもありません。
もしこの制限に引っ掛かる文字列型を扱う可能性がある場合は LongText
を利用してください。
LongTextにした場合BLOBとして保存されるため、検索時に制限があります (LongText型の検索)。
Integer型のJavaクラス
Entityの検索や更新処理で、Integer型を操作する際は、Longクラスとして値を取得・設定します(Integerクラスではありません)。
Decimal型の丸めモード
Decimal型の場合、データの保存時に丸めた値で保存されます。
「丸めモード」には以下の種類があります(java.math.RoundMode
)。
モード(java.math.RoundMode) | 説明 |
---|---|
UP |
0から離れるようにする(正数切り上げ/負数切り上げ) |
DOWN |
0に近づける(正数切り下げ/負数切り下げ) |
CEILING |
正の無限大に近づける(正数切り上げ/負数切り下げ) |
FLOOR |
負の無限大に近づける(正数切り下げ/負数切り上げ) |
HALF_UP |
四捨五入 |
HALF_DOWN |
五捨六入 |
HALF_EVEN |
銀行型丸め |
Select
Select型は選択ボックスの選択値ように、登録できる値を「値とラベル」のセットとして予め定義できるPropertyです。
値セットの定義方法は、複数のEntityで共有可能なSelectValueメタデータとして定義する方法(Global Value
)と、
それぞれのPropertyごとに個別に定義する方法(Local Value
)の2種類があります。
設定
次の項目を設定可能です。
設定項目 | 設定内容 |
---|---|
Global Value |
SelectValueメタデータを指定します。 |
Local Value |
このPropertyに特化した選択可能項目の {値、ラベル} リストを指定します。 値はString型のため、数値、Boolean値として扱う場合は注意してください。 |
Global Value と Local Value を共に設定した場合は、 Local Value が優先されます
(Global Value がクリアされた状態で保存されます)。Global Value を利用する場合は、 Local Value を全て削除して保存してください。
|
操作方法
Entityの検索や更新処理で、Select型Propertyを操作する際は、以下のクラスを利用します。
org.iplass.mtp.entity.SelectValue
EntityManager em = ManagerLocator.manager(EntityManager.class);
Entity entity = new GenericEntity("samples.Sample");
entity.setName("xxxxx");
//SelectValueの生成
SelectValue selectValue = new SelectValue("01"); //登録するためだけであれば、valueのみでOK
//SelectValueをPropertyにセット
entity.setValue("select", selectValue);
//登録
String oid = em.insert(entity);
EntityManager em = ManagerLocator.manager(EntityManager.class);
//検索(load)
String oid = "00001";
Long version = 0;
Entity entity = em.load(oid, version, "samples.Sample");
//SelectValueの取得
//取得したEntityのPropertyにはSelectValueが設定されている
SelectValue selectValue = entity.getValue("select");
System.out.println(selectValue.getValue() + "=" + selectValue.getDisplayName());
Select型のソート順
Select型に対するソートは、定義での並び順が適用されます。
value | displayName |
---|---|
98 |
未開始 |
01 |
開始中 |
02 |
終了 |
00 |
エラー |
99 |
キャンセル |
上表の順番で定義した場合、value
値でソートせず、定義した順番「未開始 ~ キャンセル」でデータがソートされます。
AutoNumber
AutoNumber型はEntityデータの登録時に自動的に値を採番するPropertyです。 日付やユーザ情報などを利用した書式設定をすることが可能です。 データ登録時以外値を変更できません(読み取り専用)。
設定
次の項目を設定可能です。
設定項目 | 設定内容 |
---|---|
開始値 |
採番を開始する番号を指定します。 既にデータが登録済みの状態でこの値を変更しても、カウンタはリセットされません。 カウンタの値をリセットしたい場合は、リセット機能を利用してください。 |
固定桁数 |
桁数を固定したい場合に指定します。 設定された桁数分、ゼロパディングした値が返されます。0を設定した場合はゼロパディングされません。 採番値が固定桁数を超えた場合は、そのまま採番値が利用されます。 |
採番ルール |
採番する際の飛び番に関するルールを指定します。
|
書式 |
登録する値をGroovyTemplate形式で書式指定することができます。 |
書式設定
書式で利用可能なバインド変数は以下のものです。
バインド変数 | 設定される値 |
---|---|
nextVal() |
次の採番された番号 |
yyyy |
年 |
MM |
月 |
dd |
日 |
HH |
時、24h表記 |
mm |
分 |
ss |
秒 |
date |
java.sql.Timestampのインスタンス |
user |
登録者User情報。 |
未指定の場合、採番された値が設定されます( ${nextVal()
と同等)。
${yyyy}-${MM}-${dd}-${nextVal()}
結果は 2018-01-01-0000001001
のようになります。
カウンタのリセット
Entityデータを他の環境からエクスポート/インポートで移行した場合は、内部で保持しているカウンタ値をリセットする必要があります。
AutoNumber型自体はUnique制約とはなっていないため、移行後の環境で重複した値が採番されてもエラーにはなりません。
AutoNumber型Propertyに対して、 OID
や Unique Index
を指定している場合は、重複が発生したタイミングでエラーになります。
現在値の取得
AdminConsole上は Current
ボタンをクリックすることで、現在のカウンタの値を表示します。
ソース上から取得したい場合は
EntityDefinitionManager#getAutoNumberCurrentValue(String definitionName, String propertyName);
を利用します。
値のリセット
AdminConsole上は Reset
ボタンをクリックすることで、「開始値」に設定された値でカウンタをリセットします。
リセットする場合は、「開始値」を変更して Reset
を実行してください。
ソース上からリセットしたい場合は
EntityDefinitionManager#resetAutoNumberCounter(String definitionName, String propertyName, long startsWith);
を利用します。
Expression
Expression型は四則演算やCase文、スカラーサブクエリ(結果が1つになるクエリ)など、
Query機能の Value Expression
として指定可能な式を設定することができるPropertyです。
設定
次の項目を設定可能です。
設定項目 | 設定内容 |
---|---|
Result Type |
式の結果として返す値のProperty型を指定します。未指定の場合はString型です。 |
式 |
指定可能な式は、Queryの |
case
when integer1 = 50 then '△△△'
when integer1 = 80 then '○○○'
else '×××'
end
integer1 / (select sum(integer1) from samples.Sample)
case
when 50 = (select integer1 + integer2 from sample.Sample on .this=this) then '△△△' (1)
when 80 = (select integer1 + integer2 from sample.Sample on .this=this) then '○○○'
else '×××'
end
1 | thisはoidとほぼ同じ意味です。逆に .oid=oid という表現は不可となっています。 |
四則演算で参照するプロパティの多重度が1以外の場合、正確な計算が実行されません。 多重度が1のプロパティに対してのみ利用してください。 |
Binary
Binary型は画像や文書ファイルなどのバイナリデータを扱うためのPropertyです。
設定
Binary型に特化した設定項目はありません。
操作方法
Entityの検索や更新処理で、Binary型Propertyを操作する際は、以下のクラスを利用します。
org.iplass.mtp.entity.BinaryReference
バイナリファイルをEntityに登録する場合は、BinaryReferenceを生成したうえでEntityにセットします。
EntityManager em = ManagerLocator.manager(EntityManager.class);
Entity entity = new GenericEntity("samples.Sample");
entity.setName("xxxxx");
//BinaryReferenceの生成
BinaryReference bin = null;
try (FileInputStream is = new FileInputStream(file)){
//EntityManagerを利用してBinaryReferenceを生成
bin = em.createBinaryReference(file.getName(), "image/gif", is);
} catch (FileNotFoundException e) {
throw new ApplicationException("ファイルが取得できません。", e);
}
//生成したBinaryReferenceをEntityにセット
entity.setValue("binary", bin);
//登録
String oid = em.insert(entity);
Entityを検索したタイミングではBinaryReferenceとしてPropertyに値がセットされています。 BinaryReferenceにはバイナリ自体は格納されていません。 BinaryReferenceに紐づくバイナリを取得したい場合はEntityManagerを利用して取得します。
EntityManager em = ManagerLocator.manager(EntityManager.class);
//検索
String oid = "00001";
long version = 0;
Entity entity = em.load(oid, version, "samples.Sample");
//BinaryReferenceの取得
//取得したEntityのPropertyにはBinaryReferenceが格納されている
BinaryReference bin = entity.getValue("binary");
//System.out.println(bin.getLobId()
// + ", name=" + bin.getName() + ", type=" + bin.getType());
//バイナリの取得(Fileとして取得する場合)
//(一時的に)保存したいdirは別途指定すること
File file = new File(dir, bin.getName());
//EntityManagerを利用してバイナリのInputStreamを取得
try (FileOutputStream fos = new FileOutputStream(file);
InputStream is = em.getInputStream(bin);
) {
//この例では「org.apache.commons.io.IOUtils」を利用
IOUtils.copy(is, fos);
} catch (IOException e) {
throw new ApplicationException("ファイルが取得できません。", e);
}
Webの画面上に表示させるような場合はimgタグを利用します。
imgタグで指定するActionを別途作成し、Resultのタイプとして Stream
を指定します。
RequestContextに対してResultの StreamAttributeName
に指定したAttributeにBinaryReferenceをセットすることで、
画像を表示することが可能になります。
(ResultのStreamタイプを利用することで、自身でStreamを取得する処理が不要になります)
この一連の実装は以下を参考にしてください。
-
Template例
jsp/gem/generic/editor/binary/BinaryPropertyEditor_View.jsp -
Action例
gem/binary/downloadこのActionクラスはJava Commandクラスに指定されたアノテーションから作成されたものです。 JavaCommandクラスは以下です。
org.iplass.gem.command.binary.DownloadCommand
ユーティリティ機能
Binaryに対する最大ファイルサイズやMagicByteチェックの実行可否、ウィルススキャンの実行可否を
service-config.xmlのWebFrontendServiceで定義できます。
設定内容の詳細は、WebFrontendServiceを参照してください。
またBinaryの永続化方法として、RDB(BLOBデータ)として保存するか、サーバ上にファイルとして保存するかを
service-config.xmlのLobStoreServiceで定義できます。
設定内容の詳細は、LobStoreServiceを参照してください。
LongText
LongText型はString型ではサイズが足りない場合(String型の文字数制限)などの テキストデータを扱うためのPropertyです。 内部的にBinary型同様Lobまたはファイルとして管理しているため、検索時に制限があります。
設定
LongText型に特化した設定項目はありません。
LongText型の検索
LongTextについては、EQLを利用した検索条件の指定は完全にはできません。 LongTextに対する完全な検索機能を提供する場合は、 全文検索 機能を利用します。 このため汎用検索画面においても検索条件としてLongText型のPropertyは表示されません。
ただし、service-config.xmlにてPropertyServiceの設定を行うことで、先頭から一定文字数分の検索が可能になります。
設定内容の詳細は、PropertyServiceを参照してください。
Reference
Reference型はEntity間の参照関係を定義するためのPropertyです。 RDBではSQLのJoinを利用してTable間の結合を定義しますが、 iPLAssのEntityではプロパティとして参照関係を定義する事で同等の機能を実現します。
Referenceの構造
オブジェクトID (oid) で少し触れましたが、Reference型は参照しているEntityの oid
と version
を保持します。

この参照関係を利用することで、参照元のEntityを検索する際に参照先のEntity情報を取得できます。
EQLではFrom句でDBのJoinのように複数Entityを結合することができません。
RDBのJoinと同様の機能をEQLで実現する場合には、対象Entityに対するReferenceプロパティを作成します。
作成したReferenceプロパティをSelect句に指定したり、Where条件で絞り込むことができます。 (Expression型など、Select句に対してスカラーサブクエリとして他Entityを参照することは可能です) |
「参照」(「順参照」)と「被参照」
Reference型には、指定した参照Entityに対する「順参照」と「被参照」という概念があります。
「順参照」は、当Entity(Referenceを定義しているEntity)が、参照Entityの、どのデータを利用するかを保持するための、当Entityの更新対象属性として扱う目的で定義します。 ですので当Entityデータを更新する際には、Entityに対してReference値を指定して更新する必要があります。
「被参照」は、当Entityが、参照Entityの、どのデータによって参照されているかを把握する目的で定義します、いわば逆引きです。 ですので当Entityを更新する際に、「被参照」として定義したPropertyに対して値を設定しても、参照関係が作成されるわけではありません。 「被参照」Propertyを定義することで、参照される側(この場合「被参照」Propertyを定義した当Entity)から参照Entityデータを取得することが可能になります。
「順参照」か「被参照」かは「被参照Property」を指定するかで決まります。
- 「被参照Property」が未指定の場合
-
「参照Entity」に対して「順参照」(「参照Entity」を参照する)
- 「被参照Property」を指定した場合
-
「参照Entity」に対して「被参照」(「参照Entity」から「被参照Property」名で参照される)
設定
次の項目を設定可能です。
設定項目 | 設定内容 |
---|---|
参照Entity |
参照関係にあるEntityを指定します。 |
参照関係 |
参照するEntityとの参照関係を指定します。 |
被参照Property、 |
このEntityが参照関係にあるEntityから参照される側(被参照)の場合に指定します。 |
参照先のバージョン |
参照先のデータとして取得するバージョンのポリシーを指定します。 |
ソート条件 |
このPropertyの多重度が1以外の場合に、どの順番で取得するかを指定します。 参照先EntityのPropertyに対して、昇順/降順を指定します。 |
参照関係の指定
参照するEntityとの関係を指定します。 指定されたタイプによって、EntityデータCRUD時の動作が変わります。
ASSOCIATION
通常の参照-
参照先Entityと特別な関係を持ちません。 このEntityデータが削除された場合、参照先のEntityデータは削除されません。
COMPOSITION
親子関係-
参照先Entityを子として参照します。 このEntityデータが削除された場合、参照先のEntityデータも削除されます。
被参照Propertyの指定
iPLAssでは、参照する側がReference型のプロパティで参照先のEntityを指定することで、参照関係を構築します。 この状態だと、参照される側がどのEntityから参照されているかを把握することができません。 参照される側が参照しているEntityを把握したい場合に「被参照Property」を利用します。 「被参照Property」をSelect句などで利用することで、参照している側の情報を取得できます。
「被参照Property」に指定可能なPropertyは、「参照Entity」で指定したEntityのProperty定義に存在する 当Entityが参照先になっているReferencePropertyです。 |
操作ログを被参照側のEntityに記録
参照情報の実態は参照する側のEntityにあります。
このため参照先EntityのCRUD操作に関する操作ログは、参照する側のEntityに保存されます。
参照される側で参照先の操作ログを把握したい場合は、「操作ログを被参照側のEntityに記録」を true
に設定します。
この設定が有効になるのは、「被参照Property」を指定した場合です。(未指定の場合、有効になりません) |
この機能の主な利用用途としては 参照関係を定義する際の考慮があります。
参照先バージョンの指定
参照先のEntityがバージョン管理されている場合に、参照データとして取得するバージョンのポリシーを指定します。
参照先のEntityがバージョン管理していない場合は、バージョンは0で上書きされるため、 ここで指定した値は意味がありません。 |
CURRENT_BASE
最新バージョンを取得-
参照先のEntityの最新バージョン(同一oid)のデータを取得します。
RECORD_BASE
保存時のバージョンを取得-
データが保存された時の参照先のEntityのバージョン(同一oid)のデータを取得します。 保存後に参照先のEntityデータが更新されても、参照する情報は保存時の状態のまま変わりません。
AS_OF_EXPRESSION_BASE
特定のバージョンを取得-
基準値に指定した条件を満たす参照先のEntityのバージョン(同一oid)のデータを取得します。
基準値の指定
「特定のバージョンを取得」を指定した場合、バージョンを特定するための基準値を指定します。 基準値は参照先Entityのバージョン管理方式により設定する値が異なります。
NUMBER BASE
の場合-
参照元Entityの数値Property名(versionなども指定可能)、または直接数値のリテラルを指定します。
TIME BASE
の場合-
参照元Entityの日時Property名(createDateなども指定可能)、または直接日時のリテラルを指定します。
操作方法
Entityの検索や更新処理で、Reference型Propertyを操作する際は、以下のクラスを利用します。
org.iplass.mtp.entity.Entity
EntityManager em = ManagerLocator.manager(EntityManager.class);
Entity entity = new GenericEntity("samples.Sample");
entity.setName("xxxxx");
//Reference用Entityの生成(登録済みであれば検索して取得してもOK)
//Entityの実装クラスGenericEntityを利用
Entity refEntity = new GenericEntity("samples.RefEntity");
refEntity.setOid("xxxxx"); //oidとversionをセットしておけばOK
refEntity.setVersion(0);
//生成したReference用EntityをEntityにセット
entity.setValue("reference", refEntity);
//MultipleのReference用Entityの生成(配列でセット)
List<Entity> multiReferences = new ArrayList<Entity>;
Entity refsEntity1 = new GenericEntity("samples.RefEntity");
refsEntity1.setOid("xxxxx");
refsEntity1.setVersion(0);
multiReferences.add(refsEntity1);
Entity refsEntity2 = new GenericEntity("samples.RefEntity");
refsEntity2.setOid("xxxxx");
refsEntity2.setVersion(0);
multiReferences.add(refsEntity2);
//参照が1件の場合でもEntityの配列でセット
entity.setValue("multiReference", multiReferences.toArray(new Entity[0]));
//登録
String oid = em.insert(entity);
多重度が1以外の場合の検索時は、loadとsearchEntityで挙動が異なります。
load時はEntityの配列で返ってきますが、searchEntity時はSearchResultの結果として、
紐付いているEntityの件数分別々のEntityレコードとして返ってきます。
(SearchResultで返ってくるListが、Referenceとして紐づいているEntityの件数分になる)
EntityManager em = ManagerLocator.manager(EntityManager.class);
//検索(load)
String oid = "00001";
long version = 0;
Entity entity = em.load(oid, version, "samples.Sample");
//Reference Entityの取得
Entity refEntity = entity.getValue("reference");
Entity[] multiRefEntity = entity.getValue("multiReference");
//検索(searchEntity)
Query query = new Query()
.select("multiReference.oid", "multiReference.name")
.from("samples.Sample")
.where(new Equals("oid", oid));
SearchResult<Entity> result = em.searchEntity(query);
System.out.println("result size = " + result.getList().size());
result.getList().forEach(entity2 -> {
Entity multiRefEntity2 = entity2.getValue("multiReference");
});
このsearchEntityの仕様により、汎用検索画面ではデフォルトとして多重度が1以外のReference Propertyは出力対象としていません。 汎用検索画面の設定で多重度が1以外のReference項目を検索結果として表示するように定義した場合は、同一のoidで複数のレコードが表示されます。
参照関係を定義する際の考慮
Entityに対して「順参照」用のReferenceプロパティを定義すると、当Entityデータの更新時に、 参照しているEntityデータ件数分の属性(oid、versionのセット)を更新しなおします。 参照先Entityの件数が少ない場合は特にレスポンス的な問題は発生しませんが、参照先Entityが大量の場合はレスポンスにも影響があります。
例えば、親子関係があるEntityで子側のEntityが大量の件数となるような場合は、子から親に「順参照」の定義をすることも1つの方法です。

この場合、親Entityの属性は親Entityの属性のみ更新するような画面を作成して対応する必要があります。 子Entityからみると親Entityに対する参照関係は1なので、更新時のレスポンスも問題ありません。
親Entityで排他制御する場合
上のように、子Entityから親Entityに対して「順参照」を定義した場合、子Entityを更新しても親Entityは更新されません。 複数の子Entityを同時に更新する可能性がある場合に、親Entity側で排他制御を行いたい時はこのままだと制御できません。
これを回避するには子Entityの更新時に親Entityを強制的に更新させます。
更新処理は子EntityのEventListenerか独自に作成したCommandで行います。
EventListenerでの実装がActionやCommandなどをカスタマイズする必要がないので容易ですが、
1処理の中で複数の子Entityを一括で親Entityに紐づけるような場合は、EventListenerではなくCommandで実装してください。
(EventListenerで実装した場合、子Entityの件数分、親Entityを更新する処理が実行されることになります)
EventListenerの beforeInsert
beforeUpdate
beforeDelete
で以下のScriptを実行します。
import org.iplass.mtp.ManagerLocator;
import org.iplass.mtp.entity.EntityManager;
import org.iplass.mtp.entity.Entity;
import org.iplass.mtp.entity.UpdateOption;
EntityManager em = ManagerLocator.manager(EntityManager.class);
//parent取得(親Entityをparentプロパティとして参照している場合)
Entity parent = entity.getValue("parent"); //対象EntityはentityとしてListenerにバインドされている
//System.out.println("parent oid=" + parent.getOid() + ",version=" + parent.getVersion());
//更新Optionを生成
UpdateOption option = new UpdateOption();
//更新Propertyを設定(例:更新日)。なにかを指定しないとNullPointerが発生する
option.setUpdateProperties(Entity.UPDATE_DATE);
//強制更新設定(変更がなくても更新)
option.setForceUpdate(true);
//parentの更新
em.update(parent, option);
被参照時の操作ログについて
子から親に「順参照」を定義する場合、ユーザがデータを操作するための詳細画面としては 子Entityの詳細画面をメインで利用するという使い方が多いと思います。 このとき詳細画面上に操作ログを表示した場合、親Entityの操作ログは子Entityの操作ログ上には表示されません。
そこで、親Entityの操作ログを子Entityの操作ログにも出力する機能が「操作履歴を被参照側のEntityに記録」チェックです。 親EntityのPropertyとして、子Entityに対する「被参照」を定義して、「操作履歴を被参照側のEntityに記録」をチェックすることで、親Entityの操作ログが子Entityの操作ログに記録されるようになり、子Entityの詳細画面から親Entityの操作ログが参照可能になります。
3.2. Validator
提供Validator
標準で提供しているPropertyのValidatorです。
Type | 説明 | Java型 |
---|---|---|
入力の有無を検証します。Propertyで設定する |
* |
|
文字列の長さを検証します。 |
String |
|
数値の範囲を検証します。 |
Number |
|
正規表現を利用して値を検証します。 |
String、Number |
|
バイナリのサイズを検証します。 |
BinaryReference |
|
バイナリのタイプを検証します。 |
BinaryReference |
|
GroovyScript書式で検証ロジックを実装します。 |
* |
対応するJava型以外のProperty型に対してValidatorを指定した場合、
検証時に EntityRuntimeException が発生します。Not Null 以外は、値が null の場合はチェックされません(true)。
|
NotNull
入力の有無を検証します。
AdminConsole上の編集画面では、Required
の設定と連動して追加、削除されます。
以下の場合にエラーとなります。
-
値が
null
-
String型の場合、値が空
-
配列の場合、サイズが0
すべての型で利用可能です。
NotNullに特化した設定項目はありません。
Length
文字列の長さを検証します。
以下の場合にエラーとなります。
-
checkBytes
がfalse
の場合、値の長さがmin
未満 -
checkBytes
がfalse
の場合、値の長さがmax
より上 -
checkBytes
がtrue
の場合、値のバイト数がmin
未満 -
checkBytes
がtrue
の場合、値のバイト数がmax
より上
String型で利用可能です。
設定項目 | 設定内容 |
---|---|
min |
最小値を指定します。 |
max |
最大値を指定します。 |
checkBytes |
バイト数でチェックする場合、trueにします。 |
Range
数値の範囲を検証します。
以下の場合にエラーとなります。
-
grater than min value
がtrue
の場合、値がmin
以下 -
grater than min value
がfalse
の場合、値がmin
未満 -
less than max value
がtrue
の場合、値がmax
以上 -
less than max value
がfalse
の場合、値がmax
より上
Number型で利用可能です。
Number型に対応するPropertyタイプは Integer
Float
Decimal
です。
設定項目 | 設定内容 |
---|---|
min |
最小値を指定します。 |
grater than min value |
最小値を含まない場合、trueにします。 |
max |
最大値を指定します。 |
less than max value |
最大値を含まない場合、trueにします。 |
Regex
正規表現を利用して値を検証します。
以下の場合にエラーとなります。
-
値が正規表現にマッチしない場合
[0-9a-zA-Z]+
[\\u3040-\\u309F]+
String型、Number型で利用可能です。
Number型の場合、 toString()
した値に対して検証します。
Number型に対応するPropertyタイプは Integer
Float
Decimal
です。
設定項目 | 設定内容 |
---|---|
pattern |
正規表現式を指定します。 |
BinarySize
バイナリのサイズを検証します。
以下の場合にエラーとなります。
-
バイナリのサイズが
min
未満 -
バイナリのサイズが
max
より上
BinaryReference型で利用可能です。
設定項目 | 設定内容 |
---|---|
min |
最小値(byte)を指定します。 |
max |
最大値(byte)を指定します。 |
BinaryType
バイナリのタイプを検証します。
以下の場合にエラーとなります。
-
バイナリのタイプが正規表現にマッチしない場合
BinaryReference型で利用可能です。
設定項目 | 設定内容 |
---|---|
acceptMimeTypesPattern |
mimeタイプを指定します(正規表現)。 |
Scripting
GroovyScript書式で検証ロジックを実装します。
以下の場合にエラーとなります。
-
scriptの戻り値が
false
すべての型で利用可能です。
設定項目 | 設定内容 |
---|---|
script |
GroovyScriptを指定します。 戻り値としてBoolean(true:OK、false:NG)を返すように実装する必要があります。 |
asArray |
多重度が1ではない場合に、value変数に配列をバインドするか、
配列分ループしてvalueにバインドするかを指定します。 |
利用可能なバインド変数は以下のものです。
バインド変数 | 設定される値 |
---|---|
entity |
対象のEntityデータ。 |
propertyName |
プロパティ名 |
value |
プロパティ値。各Propertyに対応するJava型が格納されています。 |
import org.iplass.mtp.entity.EntityManager;
import org.iplass.mtp.ManagerLocator;
import org.iplass.mtp.entity.Entity;
//値が未設定の場合はOK
if (value == null) {
return true;
}
EntityManager em = ManagerLocator.manager(EntityManager.class);
//対象のReferenceProperty
Entity refValue = (Entity)value; //valueにProperty値が入っている(バインド)
//存在チェック
Entity refData = em.load(refValue.getOid(), refValue.getVersion(), refValue.getDefinitionName());
if (refData == null) {
return false; //存在しないのでNG
} else {
return true; //存在するのでOK
}
メッセージの設定
Validateエラー時のメッセージを指定します。
メッセージの指定は、直接文字列を指定する方法とメタデータのMessageを利用する方法の2種類あります。
設定項目 | 設定内容 |
---|---|
Message(Direct) |
メッセージを直接指定します。 |
Message Category |
メタデータのMessageを選択します。メタデータのMessageを利用することで、メッセージを共有・管理することができます。 |
Code |
メッセージコードを指定します。この項目は任意です。 バッチ処理やWebサービスなどの独自処理内でコードをレスポンスとして返したい場合などに利用します。 |
Message(Direct) と Message Id が両方指定されている場合は、 Message(Direct) が優先されます。
|
メッセージ文言として、プロパティ名や値をバインド書式(${xxx}
)で参照することができます
(DirectでもメタデータのMessageでも参照できます)。
利用可能なバインド変数は以下のものです。
バインド変数 | 設定される値 |
---|---|
name |
プロパティ名 |
entityName |
エンティティ名 |
min |
Length、Range、BinarySizeの |
max |
Length、Range、BinarySizeの |
min、maxについては、他のタイプの場合はバインドされていないため ${min} 、 ${max} とそのまま出力されます。
|
Validationの操作方法
汎用画面を利用してEntityの更新処理を行う場合は、汎用画面側でValidatorエラーのハンドリングは自動的に行われます。 ここではバッチやWebサービスを利用した独自のEntity更新処理を実装する場合のValidatorエラーハンドリングの方法を説明します。
Entity更新時の操作方法
EntityManagerを利用した insert
、 update
時には
自動的にValidatorチェックが実行されます。
エラーが発生した場合は EntityValidationException
がthrowされます。
この EntityValidationException
内に、エラーとなった
ValidateError
が格納されています。
import org.iplass.mtp.entity.EntityValidationException;
import org.iplass.mtp.entity.ValidateError;
EntityManager em = ManagerLocator.manager(EntityManager.class);
try {
//登録の場合
em.insert(entity);
//更新の場合
UpdateOption option = new UpdateOption(・・・・・);
option.setUpdateProperties(・・・・・);
em.update(entity, option);
} catch (EntityValidationException e) { //EntityValidationExceptionがthrow
//ValidateErrorの取得
ValidateError[] errors = e.getValidateResult();
Arrays.stream(errors).forEach(error -> {
//対象Property名
System.out.println("propertyName =" + error.getPropertyName());
//Listなのは同一Propertyに対する複数Validator用
//エラーコードとエラーメッセージは同じサイズ
//エラーコードが未指定の場合は""
List<String> errorCodes = error.getErrorCodes();
List<String> errorMessages = error.getErrorMessages();
for (int i = 0; i < errorMessages.size(); i++) {
System.out.println(
error.getPropertyName()
+ " error = [" + errorCodes.get(i) + "]"
+ errorMessages.get(i));
}
});
}
Entityのデータ移行時など、データ更新時にValidatorチェックを行いたくない場合は、 InsertOption
、 UpdateOption
を利用します。
手動でのValidatorチェック
EntityManager#validate
を利用することで手動でValidatorチェックを実行できます。
この場合、チェック結果は「ValidateResult」として返ってきます。
import org.iplass.mtp.entity.ValidateResult;
EntityManager em = ManagerLocator.manager(EntityManager.class);
ValidateResult result = em.validate(entity); //Validatorチェックの実行
if (result.hasError()) {
//ValidateErrorの取得
ValidateError[] errors = result.getError();
・・・・・・
}
3.3. 高度な設定
インデックス設定
検索処理の高速化のためのRDBのIndexのような機能として、Propertyに対するIndexを設定できます。 Indexを設定すると検索時は高速化されますが、データ更新時のパフォーマンスに影響が発生するため、設定時は考慮が必要です。
Index設定には以下の種類があります。
タイプ | 説明 |
---|---|
NON_INDEXED |
Indexを利用しません。 |
UNIQUE |
一意のIndexを作成します。重複データを登録しようとした場合、エラーになります。 |
UNIQUE_WITHOUT_NULL |
一意のIndexを作成します。ただし |
NON_UNIQUE |
一意ではないIndexを作成します。 |
Indexに関する注意点、制約事項を説明します。
-
Property単位でのみ設定が可能です。
複合Index(複数Propertyの結合)はサポートしていません。 -
UNIQUE
、UNIQUE_WITHOUT_NULL
はEntity単位での値の重複をチェックします。
Entity更新時に重複がある場合はエラーとなります。 -
多重度が1以外のPropertyはIndexを指定できません。
-
Expression
Binary
LongText
Refernce
はIndexを指定できません。 -
Entityのバージョン管理を行う場合、
UNIQUE
、UNIQUE_WITHOUT_NULL
として指定したPropertyは変更不可になります。 Entity定義の保存時に自動的にCanEdit = false
として登録されます。 -
既に登録済みのEntityデータが存在する場合にIndex Typeを変更すると、Entity定義の保存時にIndexの再作成処理が実行されます。 大量データが登録されている場合などは考慮が必要です。
UNIQUE
、UNIQUE_WITHOUT_NULL
の場合、一意でないデータが存在すると再作成時にエラーが発生し、定義自体が保存できません。
UNIQUE
、 UNIQUE_WITHOUT_NULL
は、バックエンドでRDBのUnique Indexを利用しています。
MySQLではUnique Indexのbyte制限として767byteまでしか格納することができません。
このため、 UNIQUE
、 UNIQUE_WITHOUT_NULL
を指定した場合は、
DBの文字コードによって格納できる最大の値長に制約が発生します
(データ登録時にエラーになります)。
データ暗号化
当該カラムのデータを暗号化してDBに格納したい場合に設定します。 DB/OSなどが持つ透過的暗号化機能を利用することを推奨しますが、ライセンス費用の問題やインフラ環境で暗号化サポートしてない場合など、それらの利用が難しい場合、当該機能を利用してください。 なお、当該機能を利用する場合、アプリケーションの機能的な制限が入ります。
暗号化のモードとして以下の2つ用意をしています。
モード | インデックス化 | 暗号化強度 | 検索条件指定 | 備考 |
---|---|---|---|---|
ECBモード |
可能 |
弱い |
完全一致のみサポート |
集計はカウントのみ可能 |
CBCモード |
不可 |
強い |
不可 |
集計はカウントのみ可能 |
暗号化に関する注意点、制約事項を説明します。
-
検索は
ECBモード
の場合かつ完全一致検索のみ可能。関数の適用、ソートは不可。 -
未暗号化、暗号化を切り替えた場合、プロパティの実データは引き継がれない。
-
ECBモード
、CBCモード
を切り替えた場合、プロパティの実データは引き継がれない。 -
暗号化しているプロパティの型を変更した場合、以下のパターン以外は実データは引き継がれない。
Select型、 AutoNumber型、 Boolean型、 Integer型、 Float型、 Decimal型、 Date型、 DateTime型、 Time型 → String型
Boolean型 → Select型
暗号化していない場合と比較し、数値型間の相互変換、日付型間の相互変換、String型からLongText型への変換がされない。 -
Decimal型のscaleを変更した場合、自動的にデータの洗い替えは行われない。
プロパティ単位の暗号化を利用する場合、PropertyEncryptionServiceにて、暗号化アルゴリズムなどの設定を行ってください。
暗号化アルゴリズムは複数定義することができます。 新規に保存される値は一番後に定義された暗号化アルゴリズムを利用して暗号化されます。
4. SelectValue
SelectValueは、Entityの Select 型Propertyの選択値を定義するためのものです。
SelectValueメタデータとして定義することで、複数のEntity間や複数のProperty間で選択可能な値のセットを使いまわすことができます。
4.1. SelectValueの作成
SelectValueアイコンを右クリックして「SelectValueを作成する」を選択してください。
4.2. 設定
設定項目 | 設定内容 |
---|---|
value |
値を指定します。String型のため、数値、Boolean値として扱う場合は注意してください。 |
display name |
表示名(ラベル)を指定します。 |
5. StorageSpace
5.1. StorageSpaceについて
iPLAssでは、AdminConsoleなどを利用して、動的にEntityの定義を変更することが可能です。
これら動的に定義されたEntityのデータは、StoreServiceに定義されたStorageSpaceに格納されます。
iPLAssの初期設定では3つのStorageSpaceが定義されています。
<!-- Entity Store Settings -->
<service>
<interface>org.iplass.mtp.impl.datastore.StoreService</interface>
<property name="dataStore" class="org.iplass.mtp.impl.datastore.grdb.GRdbDataStore">
<property name="storageSpace">
<property name="storageSpaceName" value="default" />
・・・・・
</property>
<property name="storageSpace">
<property name="storageSpaceName" value="mtp" />
<property name="tableNamePostfix" value="MTP" />
・・・・・
</property>
<property name="storageSpace">
<property name="storageSpaceName" value="user" />
<property name="tableNamePostfix" value="USER" />
・・・・・
</property>
</property>
</service>
どのStorageSpaceにデータを保存するかはEntity単位で指定します。 iPLAssの標準Entityであるmtp配下のEntityは以下のStorageSpaceに保存されるようになっています。
Entity | Storage Space |
---|---|
mtp.auth.User |
user |
それ以外のEntity(mtp.*.) |
mtp |
標準で定義されているStorageSpace user 、 mtp については、基盤としての利用を前提にしているため、
アプリで作成するEntityでは利用しないでください。
|
アプリで作成するEntityについては、通常StorageSpaceが未指定のため default
というStorageSpaceに保存されます。

StorageSpaceの機能として、アプリで独自のStorageSpaceを追加することも可能になっています(service-config単位、Tenant単位ではありません)。
独自のStorageSpaceを定義することで
-
一部大量データが格納されるEntityと、その他のEntityをそれぞれ別のStorageSpace(物理テーブル)に格納することができる
-
各StorageSpace単位で物理テーブルの特性を変更することが可能なので、Entityの特性毎にうまく使い分ければ、 RDB上のテーブルスペースが効率的に利用され、RDBのファイルサイズを小さくすることができる
-
StorageSpace毎にパーティション定義内容を変更することができる
-
EntityのPropertyに対して
Store Col Name
を指定することで、 プロパティデータの物理格納カラムを独自で定義したテーブルカラムに直接格納することができる。
これを利用して複合Indexの定義などのRDBネイティブの機能を利用することができる
などのカスタマイズが可能になります。
次は、このStorageSpace定義を実際に構成するテーブル構造について説明します。
テーブル構造
StorageSpaceはそれぞれで以下のテーブルセットで構成されます。
テーブル名 | 用途 |
---|---|
obj_store |
Entityのデータを格納する汎用テーブル。動的なEntity定義に対応するため予め複数のカラムが定義されている。 |
obj_store_rb |
|
obj_ref |
Entityデータ間の参照情報を格納するテーブル。 |
obj_ref_rb |
|
obj_unique_str |
UniqueIndexが設定されたプロパティ値を格納するテーブル群。 |
obj_unique_ts |
|
obj_unique_num |
|
obj_unique_dbl |
|
obj_unique_date |
|
obj_index_str |
Indexが設定されたプロパティ値を格納するテーブル群。 |
obj_index_ts |
|
obj_index_num |
|
obj_index_dbl |
|
obj_index_date |
このテーブルセットがStorageSpaceごとに必要になります。
この中でも重要となるのが obj_store
テーブルです。
「obj_store」は
-
Entityとして定義されるすべてのデータが格納される
-
汎用的に利用するため、あらかじめ文字列型、数値型、日付型、浮動小数点型それぞれ、複数のカラムが定義されている
-
Index、UniqueIndex付のカラムもあらかじめ定義されている
-
Entityのプロパティはいずれかのカラムに自動的にマッピングされる
(テナント、Entity単位で、それぞれどのカラムにどのプロパティ値が格納されるかは異なる) -
事前にテーブルに定義されているカラム数以上のプロパティがEntityに定義された場合、PageNoを用いて1データを複数行に格納する。
という役割を持っています。
実際にデータが格納されるイメージを示します。
制御用共通カラム | プロパティ値格納用汎用カラム | Index値格納カラム | |||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
(TenantID) |
(Entity定義ID) |
(oid) |
(name) |
文字列Property |
数値Property |
IndexProperty |
|||||
tenant_id |
obj_def_id |
obj_id |
pg_no |
obj_name |
STR_1 |
STR_2 |
NUM_1 |
NUM_2 |
ISTR_1 |
ISTR_2 |
・・・ |
1 |
Product |
00001 |
0 |
productA |
string101 |
string202 |
110 |
istring101 |
istring102 |
||
1 |
Product |
00002 |
0 |
productB |
string201 |
string202 |
210 |
istring201 |
istring202 |
||
1 |
Product |
00003 |
0 |
productC |
string301 |
string302 |
310 |
istring301 |
istring302 |
||
1 |
QA |
00001 |
0 |
qa001 |
aaa |
bbb |
|||||
1 |
QA |
00001 |
1 |
ccc |
ddd |
||||||
1 |
QA |
00002 |
0 |
qa002 |
eee |
fff |
|||||
1 |
QA |
00002 |
1 |
ggg |
|||||||
1 |
Point |
00001 |
0 |
point1 |
OK |
100 |
|||||
1 |
Point |
00002 |
0 |
point2 |
NG |
200 |
Entityに定義されるPropertyの型ごとの数に対して、事前にテーブルに定義された各型ごとのカラムが足りなくなった場合は、
pg_noを利用して、複数レコードで保持します。 Query(EQL)を利用して検索されるときは、基盤内部で自動的に自己結合することで疑似的に1レコードとして返しています。 |
このようにiPLAss基盤内の仕様に沿った汎用的なテーブルを利用して、動的に定義されたEntityのプロパティデータを格納し、 EntityManagerを通してデータを制御しています。
次は、 obj_store
テーブルに対する仕様について説明します。
obj_storeの仕様
EntityManagerでEntityデータを制御するために、obj_store
テーブルの構造は一定の仕様(制約)があります。
テーブルは「システム共通項目(変更不可)」、「UniqueIndex値格納カラム」、「Index値格納カラム」、「Property値格納汎用カラム」に分かれます。
このうち「システム共通項目(変更不可)」以外は、service-configの storageSpace
定義と関連します。
標準で定義されている default
StorageSpaceをもとに説明します。
ここではMySQLの標準設定を例に説明します。RDBによって標準で定義されている値は異なります。 |
<!-- Entity Store Settings -->
<service>
<interface>org.iplass.mtp.spi.datastore.StoreService</interface>
<property name="dataStore" class="org.iplass.mtp.impl.datastore.grdb.GRdbDataStore">
・・・・
<property name="storageSpace">
<property name="storageSpaceName" value="default" />
<property name="varcharColumns" value="64" />
<property name="decimalColumns" value="32" />
<property name="timestampColumns" value="32" />
<property name="doubleColumns" value="16" />
<property name="indexedVarcharColumns" value="5" />
<property name="indexedDecimalColumns" value="4" />
<property name="indexedTimestampColumns" value="4" />
<property name="indexedDoubleColumns" value="4" />
<property name="uniqueIndexedVarcharColumns" value="2" />
<property name="uniqueIndexedDecimalColumns" value="2" />
<property name="uniqueIndexedTimestampColumns" value="2" />
<property name="uniqueIndexedDoubleColumns" value="2" />
</property>
・・・・
</property>
</service>
各Propertyについて説明します。
設定項目 | 設定内容 |
---|---|
storageSpaceName |
Entity定義で選択する際に表示されるStorage Space名を指定します。 |
tableNamePostfix |
StorageSpace用のテーブルに付加する接尾語を指定します。英数字のみ利用してください。 "obj_store" + __ + Postfix となります。アンダースコア―を2つでつなげます。 |
varcharColumns |
文字列型のプロパティを格納するための列数を指定します。 |
decimalColumns |
Decimal型のプロパティを格納するための列数を指定します。 |
timestampColumns |
Timestamp型のプロパティを格納するための列数を指定します。 |
doubleColumns |
浮動小数点型のプロパティを格納するための列数を指定します。 |
indexedVarcharColumns |
Index指定された文字列型のプロパティを格納するための列数を指定します。 |
indexedDecimalColumns |
Index指定されたDecimal型のプロパティを格納するための列数を指定します。 |
indexedTimestampColumns |
Index指定されたTimestamp型のプロパティを格納するための列数を指定します。 |
indexedDoubleColumns |
Index指定された浮動小数点型のプロパティを格納するための列数を指定します。 |
uniqueIndexedVarcharColumns |
Unique Index指定された文字列型のプロパティを格納するための列数を指定します。 |
uniqueIndexedDecimalColumns |
Unique Index指定されたDecimal型のプロパティを格納するための列数を指定します。 |
uniqueIndexedTimestampColumns |
Unique Index指定されたTimestamp型のプロパティを格納するための列数を指定します。 |
uniqueIndexedDoubleColumns |
Decimal型のプロパティを格納するための列数を指定します。 |
customPartition |
この設定はobj_storeのルールとは直接関係はありません。 obj_store${tableNamePostfix}_テナントID の命名規則に則って、テナント単位でPartitionを作成しているものです。 |
EntityのPropertyで指定された型によって、以下のカラムに値が格納されます。
カラムの型 | 対象となるEntityプロパティの型 |
---|---|
Varchar |
AutoNumber、Boolean、Select、String、LongText、Binary |
Timestamp |
Date、Datetime、Time |
Decimal |
Decimal、Integer |
Double |
Float |
このようにservice-configに定義されたStorageSpace定義に沿った obj_store
を作成することで、
EntityManagerがEntityデータを自動的に制御します。
5.2. カスタマイズ
「obj_storeの仕様」に則って obj_store
テーブルを作成することで、独自のStorageSpaceを利用することができます。
これによって、例えば、
-
大量データが格納されるEntityのために
order
StorageSpaceを準備し、 OrderEntityはorder
StorageSpaceに格納する -
プロパティ数が少ないEntity用に
small
StorageSpaceとして、文字列型、数値型、日付型のカラムを3個ずつだけ定義する -
数値型のPropertyが多いEntity用に
num
StorageSpaceとして、数値型のカラムを300個定義して、日付型は1個だけにする
など、Entityの特性毎にうまく使い分ければ、RDB上のテーブルスペースが効率的に利用され、RDBのファイルサイズを小さくすることができます。
また、汎用カラム数がオーバーした場合に利用される pg_no
による疑似レコード化も抑えることができます。

独自のStorageSpaceを作成するには、service-configのStorageSpace定義に対応するStorageSpace用のテーブルセットを作成する必要があります。
このDDLを生成するためのツールとして、「Custom Storage Space」ツールを提供しています。 このツールで生成されたDDLをデータベースに反映すれば、独自のStorageSpaceが利用できるようになります。
ツールの利用方法は Custom Storage Spaceを参照してください。
5.3. カラムマッピング
Entityのプロパティ定義では、 Store Col Name
という属性を指定することができます。
この機能は、StorageSpaceに紐ずく obj_store
テーブルに独自のカラムを定義することで、そのカラムにプロパティ値を保存する機能です。
この値が未指定の場合は、プロパティの型とStorageSpace定義をもとにして基盤内部で「Property値格納汎用カラム」に自動的に値を格納します。
言いかえれば、 Store Col Name
が未指定の場合は、どのカラムにデータが格納されているかはアプリ側では判断できません。
カラムマッピング機能により
-
汎用カラムの文字列型は「TEXT」(MySQLの場合)として定義しているが、 独自のカラムでは「VARCHAR(3)」として定義することで、テーブルスペースを効率的に利用できる。
-
独自カラムを指定することで、
obj_store
のどのカラムに値が格納されるかが判断できる。
例えば複合Indexを作成したり、Partitionを作成する際のKEYとして指定することができるなど、RDBネイティブの機能が利用できる。
(年度カラムを定義して、テナント+年度などでPartitionを分けるなど)
といったことが可能になります。
極端な例としては、
あるEntityに特化したStorageSpaceを作成して、全てのプロパティに対して独自カラムを作成して、
プロパティで Store Col Name
を定義すれば、「システム共通項目(変更不可)」以外は不要になります。
obj_store
に対して独自のカラムを作成する場合は、
「カスタマイズ」で説明した手順を実施して作成されたDDLに対して追加してください。
以下の点に注意してください。
-
カラムの追加が必要なのは
obj_store
、obj_store_rb
(削除データ格納用)テーブルの2つです。
このテーブルのカラムは同期している必要があります。(データを物理削除するのみの場合はrbは利用されません) -
独自で追加するカラムの名前には、「STR_1」「NUM_1」「TS_1」「DBL_1」など、基盤が自動割当てに利用する名前は利用しないでください。
5.4. Entity定義の変更時の注意点
Entity定義を更新する場合には以下の点に注意してください。
既に登録済のデータは変更後のStorageSpaceに移動しません。
もしデータを移行したい場合は、「Storage Space Migration」ツールを利用するか、
変更前にPackageやEntityExplorerなどでエクスポートしたあとにStorageSpaceを変更し、インポートを行ってください。
ツールの利用方法は Storage Space Migrationを参照してください。
基本的にデータの更新・ロックは発生しません。
ただし、プロパティ追加に伴ってページの追加が必要になった場合は、データに対してレコードロックが掛ります。
-
データ型を変更した場合
データの変換が可能な場合、データの値は引き継がれます。 ただし、データに対してレコードロックが掛ります。
データの変換が不可能な場合、データの値は引き継がれません。 このため基本的にはデータに対してロックは掛りません。
ただし、新しいデータ型に合わせて新しくカラムが割り当てられるため、 この結果としてページの追加が必要になった場合は、レコードロックが掛ります。 -
Index定義を変更した場合
データに対してレコードロックが掛ります。
-
相互変換可能
プロパティ型 補足 DECIMAL ⇔ INTEGER ⇔ FLOAT
桁数に応じての四捨五入等は発生
DATE ⇔ DATETIME
時間部分は00:00:00で補完
TIME ⇔ DATETIME
日付部分は1970-01-01で補完
AUTONUMBER ⇔ STRING
-
一方向のみ変換可能
プロパティ型 補足 * ⇒ STRING
LONGTEXT,BINARY除くすべての型はSTRINGに変換可能
STRING ⇒ LONGTEXT
STRING型にて格納されている文字列のうち、DBのVARCHARカラムのバイト数-21バイト以上の文字は切り捨てされる。
Oracleの場合3979byte以上の文字は切り捨てされるBOOLEAN ⇒ SELECT
SELECT型の値としては、false→0、true→1になる
6. 全文検索
6.1. 概要
全文検索とは、Entity 及び Entity内の列への横断検索できる機能です。
例えば、既存のEQLを使った場合は以下のようになります。
複数の列に対して検索する → 対象の列の数だけWHERE句を書く必要がある 複数のEntityに対して検索する → 結合または複数回のEQLを実行する必要がある
全文検索を使えば、開発者が上記のロジックを組まなくても横断的な検索結果を取得することが可能です。
ただし、全文検索はリアルタイムでデータが反映されるわけではありません。ご注意ください。 |
iPLAssでは、Lucene(ルシーン)とSolr(ソーラー)という全文検索エンジンを利用しており、設定でどちらかを利用することが可能です。
各エンジンの簡単な差は下記を参照してください。
Lucene | Solr | |
---|---|---|
概要 |
100% PureJavaで作成された、インデックス作成タイプの全文検索ライブラリ。 |
Luceneをベースに、管理画面やキャッシュ機構を取り入れたアプリケーション。 |
データ保存先 |
ファイル |
Solrサーバ内 |
Analyzer(※)の扱いやすさ |
デフォルトで使えるAnalyzerを適用する場合は、とても簡単。(複数種類有) |
Analyzerはないため、Tokenizer/Filterを個別に設定する必要がある。 |
全文検索では、以下の2種類のクラス(Tokenizer/Filter)を組み合わせて、文字の分割を行います。
Analyzerを利用することで、すでに決まったクラス・決まった順序で文字の組み合わせができるようになります。
-
Tokenizer
検索対象値(Entityに登録されているデータ等)や検索文字列(検索キーワードとして入力された文字列)を、検索のための文書の最小要素(Token)へ分割するクラスです。
検索結果にヒットする条件は、検索対象値と検索文字列それぞれのTokenが一致することとなるため、Tokenizerの指定により検索の使い勝手が変わります。
例えば、「関西国際空港」という文字列があったとします。指定するTokenizerにより生成されるTokenは、以下のパターン等に分かれます。-
「関西国際空港」
(「関西国際空港」を1つの検索文字列として扱われます。この場合、検索文字列に「関西」と入力してもヒットしません) -
「関西」「国際」「空港」
(意味のある文字列に分割します。これにより、「関西」、「国際」、「空港」のいずれかの入力でヒットします) -
「関西」「西国」「国際」「際空」「空港」「港」
(左記のように2文字ずつに分割します。これにより、上記よりもヒットする文字列の数は多くなります)
※ただし「東京都庁」のような場合は、「京都」という検索文字列でもヒットする、などの意図しないヒットが発生しやすいです
-
-
Filter
表記ゆれの補完や検索文字として適さない文字列の削除などを行うクラスです。
例えば、Lucene側でいえば以下のようなFilterが存在します。-
JapaneseKatakanaStemFilter
4文字以上のカタカナの長音を除去します。「サーバー」は「サーバ」とも補完され、検索文字列にどちらを入力してもヒットします。 -
CJKWidthFilter
半角カナは全角カナへ、全角英数は半角英数へ補完され、補完後の文字列でヒットするようになります。
-
-
利用バージョン
利用しているバージョンは以下の通りです。iPLAss lucene Solr 3.0.0 ~
7.4.0
6.2.1
バージョンは上記表を元にURLからダウンロードしてください。
※過去バージョンもこちらのURLから辿ることができます。該当バージョンのフォルダをクリック後、zipファイルをダウンロードしてください。
各jarは解凍後のルートから下記の通りの場所に配置してあります。jar名 ディレクトリ lucene-analyzers-common-x.x.x.jar
lucene-x.x.x/analysis/common
lucene-analyzers-kuromoji-x.x.x.jar
lucene-x.x.x/analysis/kuromoji
lucene-analyzers-smartcn-x.x.x.jar
lucene-x.x.x/analysis/smartcn
lucene-core-x.x.x.jar
lucene-x.x.x/core
6.2. 設定
Lucene設定
-
service-config.xmlの設定
-
デフォルトのAnalyzerを利用する場合
デフォルトの全文検索(Lucene)を利用する場合、下記設定を確認してください。<!-- 全文検索で利用するService --> <service> <interface>org.iplass.mtp.impl.fulltextsearch.FulltextSearchService</interface> <property name="useFulltextSearch" value="true" /> <property name="maxRows" value="10" /> <property name="throwExceptionWhenOverLimit" value="false"/> <!-- lucene利用 --> <class>org.iplass.mtp.impl.fulltextsearch.FulltextSearchLuceneService</class> <property name="directory" value="D:\USER\Data\lucene" /> <property name="analyzer" value="org.apache.lucene.analysis.ja.JapaneseAnalyzer" /> </service>
プロパティ名 内容説明 useFulltextSearch
false:全文検索機能が無効になります。
true:全文検索機能が有効になります。maxRows
全文検索サーバから取得する検索結果の最大件数を設定します。
※件数が1000件以上で、かつ、Oracleを利用する場合は、Oracle設定の「enableInPartitioning」プロパティ値を「true」へ変更してください。throwExceptionWhenOverLimit
false:maxRowsの設定値以上に検索結果件数が取得できた場合でも、maxRowsの設定値分の件数は結果を表示します。
※画像は設定値以上に取得出来た場合となります。設定値未満の場合、メッセージ表示はありません。
true:maxRowsの設定値以上に検索結果件数が取得できた場合、結果を表示せずに条件を絞り込むようメッセージで催促されます。
directory
indexを保存するディレクトリを指定します。
analyzer
利用するAnalyzerを指定します。
デフォルトで指定可能なAnalyzerは以下のとおりです。
(AnalyzerはLuceneが配布している別のjarを追加することで、Analyzerを増やすことも可能です)デフォルトのAnalyzer内に定義されているFilterはすべて、Tokenizer実行後に呼び出されます。 -
org.apache.lucene.analysis.core.WhitespaceAnalyzer
空白分割指定することで実行されるTokenizer/Filter:-
WhitespaceTokenizer
空白を利用して分割します。
-
-
org.apache.lucene.analysis.core.SimpleAnalyzer
アルファベット分割指定することで実行されるTokenizer/Filter:-
LetterTokenizer
非文字を利用して分割します。 -
LowerCaseFilter
英字の大文字を小文字に変換します。
-
-
org.apache.lucene.analysis.core.StopAnalyzer
ストップワード分割指定することで実行されるTokenizer/Filter:-
LetterTokenizer
非文字を利用して分割します。 -
LowerCaseFilter
英字の大文字を小文字に変換します。 -
StopFilter
指定文字を除外します。除外対象となるTokenは*※1*参照してください。
-
-
org.apache.lucene.analysis.standard.StandardAnalyzer
高度分割(Eメール・アドレス・頭字語・中国語・日本語・韓国語・英数字など)指定することで実行されるTokenizer/Filter:-
StandardTokenizer
Unicode Standard Annex #29(※2)で定められる語の境界ルールに従って分割します。 -
StandardFilter
StandardTokenizerで抽出したTokenを正規化します。 -
LowerCaseFilter
英字の大文字を小文字に変換します。 -
StopFilter
指定文字を除外します。本Analyzerでも除外TokenはStopAnalyzerと同じです。
-
-
org.apache.lucene.analysis.cjk.CJKAnalyzer
Bi-gram分割(文章が分かち書きされない言語である中国語、日本語および韓国語向け)指定することで実行されるTokenizer/Filter:-
StandardTokenizer
Unicode Standard Annex #29(※2)で定められる語の境界ルールに従って分割します。 -
CJKWidthFilter
半角カナは全角カナへ、全角英数は半角英数へ補完します。 -
LowerCaseFilter
英字の大文字を小文字に変換します。 -
CJKBigramFilter
漢字、ひらがな、カタカナ、ハングルをbi-gramに変換します。 -
StopFilter
指定文字を除外します。除外対象となるTokenは*※3*を参照してください。(jar内のstopwords.txtより)
-
-
org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer
中国語分割(簡体字中国語または中国語と英語が混在している文字列に有効)指定することで実行されるTokenizer/Filter:-
HMMChineseTokenizer
確率的知識といわれるものを利用して分割します。 -
PorterStemFilter
半角英字系の文字列の揺れを補完します。(boxes→boxなど。ただし、was→waという事例も) -
StopFilter
指定文字を除外します。除外対象となるTokenは*※3*を参照してください。(jar内のstopwords.txtより)
-
-
org.apache.lucene.analysis.ja.JapaneseAnalyzer
日本語分割(Searchモード)指定することで実行されるTokenizer/Filter:-
JapaneseTokenizer
形態素解析といわれるものを利用し分割後、複合語で構成された単語をさらに細かく分割します。 -
JapaneseBaseFormFilter
動詞などを基本形へ置き換えます。(書き→書く、した→するなど) -
JapanesePartOfSpeechStopFilter
指定した品詞を除外します。除外対象となる品詞は*※4*参照してください。 -
CJKWidthFilter
半角カナは全角カナへ、全角英数は半角英数へ補完します。 -
StopFilter
指定文字を除外します。除外対象となるTokenは*※5*参照してください。 -
JapaneseKatakanaStemFilter
4文字以上のカタカナの長音を除去します。 -
LowerCaseFilter
英字の大文字を小文字に変換します。
-
-
org.iplass.mtp.impl.fulltextsearch.JapaneseNormalAnalyzer
日本語分割(Normalモード):形態素解析を利用して分割します。その他はSearchモードと同様です。(※6) -
org.iplass.mtp.impl.fulltextsearch.JapaneseExtendedAnalyzer
日本語分割(Extendedモード):Searchモードと同様の分割を行いつつ、辞書にない未知語をuni-gramに分割します。※1 Luceneのjar内のstopwords.txtより
a, an, and,are, as, at, be, but, by, for, if, in,into, is, it, no, not, of, on, or, such,that, the, their, then, there, these, they,this, to, was, will, with※2 ※3 SmartChineseのjar内のstopwords.txtより
, . ` - _ = ? ' | " ( ) { } [ ] < > * # & ^ $ @ ! ~ : ; + / \ 《 》 — - , 。 、 : ; ! · ? “ ” ) ( 【 】 [ ] ●※4 Kuromoji(日本語分割)のjar内のstoptags.txtより
接続詞, 助詞, 助詞-格助詞, 助詞-格助詞-一般, 助詞-格助詞-引用, 助詞-格助詞-連語, 助詞-接続助詞, 助詞-係助詞, 助詞-副助詞, 助詞-間投助詞, 助詞-並立助詞, 助詞-終助詞, 助詞-副助詞/並立助詞/終助詞, 助詞-連体化, 助詞-副詞化, 助詞-特殊, 助動詞, 記号, 記号-一般, 記号-読点, 記号-句点, 記号-空白, 記号-括弧開, 記号-括弧閉, その他-間投, フィラー, 非言語音※5 Kuromoji(日本語分割)のjar内のstopwords.txtより
の, に, は, を, た, が, で, て, と, し, れ, さ, ある, いる, も, する, から, な, こと, として, い, や, れる, など, なっ, ない, この, ため, その, あっ, よう, また, もの, という, あり, まで, られ, なる, へ, か, だ, これ, によって, により, おり, より, による, ず, なり, られる, において, ば, なかっ, なく, しかし, について, せ, だっ, その後, できる, それ, う, ので, なお, のみ, でき, き, つ, における, および, いう, さらに, でも, ら, たり, その他, に関する, たち, ます, ん, なら, に対して, 特に, せる, 及び, これら, とき, では, にて, ほか, ながら, うち, そして, とともに, ただし, かつて, それぞれ, または, お, ほど, ものの, に対する, ほとんど, と共に, といった, です, とも, ところ, ここ※6 Kuromoji(日本語分割)のモードごとについての参考URL
http://d.hatena.ne.jp/Kazuhira/20130602/1370163286
-
-
Analyzerをカスタマイズして利用する場合
カスタマイズの全文検索(Lucene)を利用する場合、下記設定を確認してください。<!-- 全文検索で利用するService --> <service> <interface>org.iplass.mtp.impl.fulltextsearch.FulltextSearchService</interface> <property name="useFulltextSearch" value="true" /> <property name="maxRows" value="10" /> <property name="throwExceptionWhenOverLimit" value="false"/> <!-- lucene利用 --> <class>org.iplass.mtp.impl.fulltextsearch.FulltextSearchLuceneService</class> <property name="directory" value="D:\USER\Data\lucene" /> <!-- 独自パラメータを利用しない場合 --> <property name="analyzer" value="xx.xx.xxxxx.XxxAnalyzer" /> <!-- 独自パラメータを利用する場合 --> <property name="analyzer" class="xx.xx.xxxxx.XxxAnalyzer" > <property name="bean" class="fulltext.TestBean" > <property name="property1" value="D:\lucene\cstmStopwords.txt" /> <property name="property2" value="false" /> </property> </property> </service>
プロパティ名 内容説明 analyzer
利用するカスタマイズAnalyzerを指定します。作成方法は後述を参照してください。
(独自パラメータを利用しない場合はvalue値に、する場合はclass値にクラス名を記載してください。)bean
独自パラメータの情報を保持するクラスを指定します。
name, value など
独自パラメータ名はbean内のフィールド名に対応した名前をpropertyのname値に設定してください。
-
独自パラメータなしのカスタマイズAnalyzerクラスの作成
package xx.xx.xxx; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.Tokenizer; import org.apache.lucene.analysis.cjk.CJKWidthFilter; import org.apache.lucene.analysis.core.LowerCaseFilter; import org.apache.lucene.analysis.core.StopFilter; import org.apache.lucene.analysis.ja.JapaneseAnalyzer; import org.apache.lucene.analysis.ja.JapaneseBaseFormFilter; import org.apache.lucene.analysis.ja.JapaneseKatakanaStemFilter; import org.apache.lucene.analysis.ja.JapanesePartOfSpeechStopFilter; import org.apache.lucene.analysis.ja.JapaneseTokenizer; import org.iplass.mtp.spi.Config; import org.iplass.mtp.spi.Service; import org.iplass.mtp.spi.ServiceInitListener; public class XxxxAnalyzer extends Analyzer implements ServiceInitListener { public XxxxAnalyzer() { // 全プロパティに同じTokenizer/Filterを適用する場合 // super(GLOBAL_REUSE_STRATEGY); (1) // プロパティ毎にTokenizer/Filterを適用する場合 // super(PER_FIELD_REUSE_STRATEGY); (2) } @Override public void inited(Service service, Config config) { } @Override public void destroyed() { } @Override (4) protected TokenStreamComponents createComponents(String propertyName) { (3) Tokenizer tokenizer = new JapaneseTokenizer(null, true, JapaneseTokenizer.Mode.SEARCH); TokenStream stream = new JapaneseBaseFormFilter(tokenizer); stream = new JapanesePartOfSpeechStopFilter( stream, JapaneseAnalyzer.getDefaultStopTags() ); stream = new CJKWidthFilter(stream); stream = new StopFilter( stream, JapaneseAnalyzer.getDefaultStopSet() ); stream = new JapaneseKatakanaStemFilter(stream); stream = new LowerCaseFilter(stream); return new Analyzer.TokenStreamComponents(tokenizer, stream); } @Override (5) protected TokenStream normalize(String fieldName, TokenStream in) { TokenStream result = new CJKWidthFilter(in); result = new LowerCaseFilter(result); return result; } }
- ※1
-
GLOBAL_REUSE_STRATEGY
全プロパティ(Entityの列)に対し、同じTokenizer/Filterを適用します。
(Index付与時や検索時に1度だけTokenizer/Filterの定義が呼ばれます) - ※2
-
PER_FIELD_REUSE_STRATEGY
プロパティ毎にTokenizer/Filterが適用されるようにします。
(Index付与時や検索時に、対象プロパティの数だけTokeinzer/Filterの定義が呼ばれます) デフォルトではfalseとなっているため、変更しない場合は定義不要です。 - ※3
-
この引数値がプロパティ名となります。
プロパティ毎に設定する場合、この値を利用して内部分岐が可能になります。取得できるプロパティ名はiPLAssで定義した物理名となり、また、Entity毎に処理を分岐することはできません。 - ※4
-
Override必須メソッド。
このメソッド内をカスタマイズすることで、任意のTokenizer/Filterを組み合わせて全文検索を利用することができます。
※サンプルソースAnalyzer:org.apache.lucene.analysis.ja.JapaneseAnalyzer
を設定した場合と同等の処理
その他利用できるクラスは、下記URL等をご覧ください。http://www.mwsoft.jp/programming/lucene/lucene_filter.html
http://lucene.apache.org/core/7_4_0/core/index.html
http://lucene.apache.org/core/7_4_0/analyzers-common/index.html
http://lucene.apache.org/core/7_4_0/analyzers-kuromoji/index.html
http://lucene.apache.org/core/7_4_0/analyzers-smartcn/index.html - ※5
-
Override必須メソッド。
このメソッド内をカスタマイズすることで、引数として検索文字列のTokenStreamに対して、NormalizationのFilterを適用することが出来ます。
Stemmingのものを適用しないべきです。下記のURLでJavaDocのサンプルコードを参照してください。
-
独自パラメータありのカスタマイズAnalyzerクラスの作成
package xx.xx.xxx; import (略) public class XxxxAnalyzer extends Analyzer implements ServiceInitListener { private XxxxBean config; (1) public XxxxAnalyzer() {} (2) public void setBean(XxxxBean config) { (1) this.config = config; } @Override public void inited(Service service, Config config) { } @Override public void destroyed() { } @Override (3) protected TokenStreamComponents createComponents(String propertyName) {} @Override (4) protected TokenStream normalize(String fieldName, TokenStream in) {} }
1 設定ファイルに定義したプロパティ名をフィールドに持つBeanクラスを作成したクラス内で持ち、setterを追加してください。 2 i-1、i-2と同様。 3 i-4と同様。 4 i-5と同様。 package xx.xx.xxx; public class XxxxBean { private String property1; private boolean property2; public String getProperty1() { return property1; } public void setProperty1(String property1) { this.property1 = property1; } public boolean getProperty2() { return property2; } public void setProperty2(boolean property2) { this.property2 = property2; } }
1-bの設定ファイルのように記載した場合、property1、property2がそれぞれ設定された状態になります。
private String property1 = "D:\lucene\cstmStopwords.txt"
private boolean property2 = false
-
-
Solr設定
-
service-config.xmlの設定
下記設定を確認してください。<!-- 全文検索で利用するService --> <service> <interface>org.iplass.mtp.impl.fulltextsearch.FulltextSearchService</interface> <property name="useFulltextSearch" value="true" /> <property name="maxRows" value="10" /> <property name="throwExceptionWhenOverLimit" value="false"/> <!-- solr利用 --> <class>org.iplass.mtp.impl.fulltextsearch.FulltextSearchSolrService</class> <property name="solrUrl" value="http://{ADDRESS}:{PORT}/solr/{CoreName}/" /> </service>
プロパティ名 内容説明 useFulltextSearch
false:全文検索機能が無効になります。
true:全文検索機能が有効になります。maxRows
全文検索サーバから取得する検索結果の最大件数を設定します。
※件数が1000件以上で、かつ、Oracleを利用する場合は、Oracle設定の「enableInPartitioning」プロパティ値を「true」へ変更してください。throwExceptionWhenOverLimit
false:maxRowsの設定値以上に検索結果件数が取得できた場合でも、maxRowsの設定値分の件数は結果を表示します。
※画像は設定値以上に取得出来た場合となります。設定値未満の場合、メッセージ表示はありません。
true:maxRowsの設定値以上に検索結果件数が取得できた場合、結果を表示せずに条件を絞り込むようメッセージで催促されます。
solrUrl
利用するSolrサーバのURL
-
schema.xmlの設定
有償版のSDKに同梱されている
iplass-ee-solr-XXX.jar
ファイルを解凍し、schema\solr
ディレクトリ下のschema.xml
を取得します。schema.xmlは、検索対象値の保持方法や分割方法の情報が定義されています。
対象ファイルはサーバ構築時に作成されたcore(以下の画像であれば、「collection1」)/confの下に配置するファイルとなります。下記はschema.xmlの一部抜粋したものになります。
<?xml version="1.0" encoding="UTF-8" ?> <schema name="iPLAss" version="1.4"> : : <fieldType name="text_sen" class="solr.TextField" positionIncrementGap="100" > (1) <analyzer> (2) <charFilter class="solr.MappingCharFilterFactory" mapping="lang/mapping_ja.txt"/> (3) <tokenizer class="solr.JapaneseTokenizerFactory" mode="SEARCH" discardPunctuation="true" /> <filter class="solr.JapaneseBaseFormFilterFactory"/> <filter class="solr.JapanesePartOfSpeechStopFilterFactory" tags="lang/stoptags_ja.txt"/> <filter class="solr.CJKWidthFilterFactory"/> <filter class="solr.StopFilterFactory" ignoreCase="true" words="lang/stopwords_ja.txt" /> <filter class="solr.JapaneseKatakanaStemFilterFactory" minimumLength="4"/> <filter class="solr.LowerCaseFilterFactory"/> <filter class="solr.SynonymFilterFactory" synonyms="lang/synonyms_ja.txt" ignoreCase="true" expand="true"/> </analyzer> </fieldType> : : <fields> <field name="V_1" type="text_sen" indexed="true" stored="true" omitNorms="true" multiValued="true" /> (1) <field name="V_2" type="text_sen" indexed="true" stored="true" omitNorms="true" multiValued="true" /> </fields> </schema>
1 この紐付きが一致するプロパティに対して、上記で定義したTokenizer/Filterが適用されます。
フィールドごとに変更した場合は、別途fieldTypeを作成し紐付けるようにしていただくことで実現可能になります。2 この部分をカスタマイズすることで、任意のTokenizer/Filterを組み合わせて全文検索を利用することができます。 3 サーバ構築時に作成されたcoreのinstanceDirの conf/lang
ディレクトリの下にTokenizer/Filterに適用するxxx.txtファイルを入れます。※サンプル定義: LuceneのデフォルトAnalyzerである
org.apache.lucene.analysis.ja.JapaneseAnalyzer
をSolrで類似実現する場合の定義例
(charFilterのクラスはorg.apache.lucene.analysis.ja.JapaneseAnalyzer
にはない)
(xxx.txt類は各自用意したものを想定)その他利用できるclass値については以下URL等をご覧ください。
http://wiki.apache.org/solr/AnalyzersTokenizersTokenFilters
http://lucene.apache.org/solr/6_2_1/solr-core/index.html
http://lucene.apache.org/core/6_2_1/core/index.html
http://lucene.apache.org/core/6_2_1/analyzers-common/index.html
http://lucene.apache.org/core/6_2_1/analyzers-kuromoji/index.html
http://lucene.apache.org/core/6_2_1/analyzers-smartcn/index.html※Lucene側のAPIに関しては、xxxxFactoryというものがSolrで設定できるクラスとなっております。
StopAnalyzer
Luceneで指定できるAnalyzer
StopFilter
Luceneで指定できるFilter
StopFilterFactory
Solrで指定できるFilter
<fieldType>タグ内の各タグについて
-
<analyzer>タグ
Tokenizer/Filterを定義するための親タグです。
また以下のように定義することも可能です。<analyzer type="index"> 検索対象値を保持する前に適用されるTokenizer/Filterの定義します。 ・・・・ </analyzer> <analyzer type="query"> 検索文字列を検索対象値と比較する前に適用されるTokenizer/Filterを定義します。 ・・・・ </analyzer>
-
<charFilter>タグ
Tokenizer実行前に呼ばれるFilterを定義します。 -
<tokenizer>タグ
実行するTokenizerを定義します。 -
<filter>タグ
Tokenizer実行後に呼ばれるFilterを定義します。
-
class値以外の要素(modeやtagsなど)は指定するclassにより異なりますので、ご注意ください。 |
-
Solrサーバに関する補足
Tokenizer/FilterはSolrサーバ本体だけでは動作しないものがあります。
例えば、schema.xmlに以下の定義がある場合、: : <fieldType name="text_chinese" class="solr.TextField"> <analyzer> <tokenizer class="org.apache.lucene.analysis.cn.smart.HMMChineseTokenizerFactory"/> <filter class="solr.LowerCaseFilterFactory" /> </analyzer> </fieldType> : :
この場合は、サーバ構築時に作成されたcoreのinstanceDir(以下の画像であれば、「collection1」)下に
lib
ディレクトリを作成し、そのディレクトリにjarを追加で配置してください。
6.3. 表示方法
-
インターセプターの設定
service-config.xmlに以下設定を追加してください。<service> <interface>org.iplass.mtp.impl.entity.EntityService</interface> <property name="interceptor" class="org.iplass.mtp.impl.entity.fulltextsearch.FulltextSearchInterceptor" additional="true" /> </service>
-
Indexの設定
AdminConsoleからIndex対象とするEntity、および、Entityの列の設定をします。
全文検索対象としたいEntityを開き、「crawl for full text search」にチェックしてください。
すると、デフォルトでIndex対象となりうるプロパティの「Crawl」列にチェックが出ます。
各プロジェクトで必要なプロパティに対してのみチェックがあることを確認し、保存してください。
※typeがBinaryであるプロパティクを全文検索対象とした場合、バイナリのファイル名 + " " + バイナリのファイルタイプ
という値で登録されます。
-
Indexの作成
全文検索で検索が行われるデータは下記のIndex作成をした時点でのデータとなります。(ただし取得(表示)されるデータは、検索時点の最新データとなります)
そのため、新しく登録したデータをIndexに含めたいなどの場合は、必ずIndexの再作成を実施してください。-
AdminConsoleから
AdminConsole画面の左下メニューにあるToolsのEntityExplorerを選択します。
全文検索を利用する設定になっている場合、「Entity Crawl」タブが表示されます。
「Entity Crawl」タブのリストには「crawl for full text search」にチェックをつけたEntityのみが表示されます。クローリングには選択したEntityのみを対象に実施する方法と、全Entityを全てクローリングする2種類があります。
A. 任意のEntityのみを対象としてクローリングしたい場合はリストのEntityにチェックをいれ、
Start Crawl
ボタンをクリックして下さい。B. クローリング対象Entityを全てクローリングしたい場合は
Re Crawl All Entity
ボタンをクリックして下さい。この場合、チェックをいれていないEntityも全てが対象となります。C. クローリング処理が完了しましたら、INDEXデータの変更を反映させるために、
Refresh
ボタンをクリックしてください。 -
バッチから
配布しているiPLAss SDKのiplass-tools-batch/src/main/sh/start_entitydata_crawl.sh
をクーロン等にセットすることで、バッチ起動が可能です。 ※尚上記shには以下の内容が設定可能です。
-
オプション
-sとすることでサイレントモードで起動可能です。 -
引数
テナントIDを指定する事で対象テナントのみクローリング可能です。スケジュール起動するバッチとした場合は-sオプションを指定し、引数はなしで実行する事で、定期的に全テナントに対してクロール処理を実行します。
クロール対象となるEntityは前述のindexの設定に記載した内容で設定したEntityのみとなります。(例)$ ./start_entitydata_crawl.sh -s
-
-
-
検索の実施
-
画面からの検索
全文検索機能を有効にしている場合のみ画面上部に拡大鏡マークが表示されます。
拡大鏡マークをクリックすると、検索プルダウンが表示されます。
また、このプルダウンに表示されるエンティティはAdminConsoleでIndex対象としたEntityのみとなります。
プルダウン右にあるテキストボックスに文字列を入力して検索することで全文検索が実行されます。
エンティティを選択しない場合はIndex対象とした全Entityが対象なり、下記のような検索結果画面となります。(参考)ソートについて
全文検索機能でのソートは以下のようになっています。第1ソート:スコア(降順)
第2ソート:Entity定義名(昇順)スコアとは、検索文字列と検索対象値(行単位)の関連度が数値化されたものとなります。
これらはSolr/Lucene内部で算出された値を利用しています。
簡単に条件を表すと、以下に一致すればするほどスコア値が高くなる傾向があります。-
検索文字列の単語がより多く含まれている
-
検索対象の値が短い
-
全検索対象の中で希少単語が含まれている
「検索対象の値が短い」の例: 実行環境として、全文検索の取得上限(maxRows設定)を「5」に設定し、「java」という文字列が3つ出てくる情報を4つ、2つ出てくる情報(緑枠の部分)を3つ用意している状態です。
(全文検索対象のプロパティは「検索対象1」~「検索対象3」)
スコア値が高くなる傾向の1つである「検索文字列の単語がより多く含まれている」が適用されたことにより、「java」という文字列が2つ出てくる情報は1件分しか表示できません。
「java」という文字列が2つ出てくる情報の種類として、1件はプロパティに設定した値が「java」だけのもののみ、その他2件はjavaの他に文字列を含んでいる値になっています。
「検索対象の値が短い」という条件が適用されたことにより、「java」だけ登録した値がスコアとして高くなり、全文検索結果として表示されています。 -
-
検索の実装方法
-
全エンティティを対象に検索する場合
EntityManagerのfulltextSearchEntityを利用して下さい。
複数のEntityに対して横断的に一括で検索します。
ただし、取得できるデータはEntity毎にマージされたものとなります。 -
EQLの検索条件として全文検索条件を利用する場合
下記のようにEQLの条件中に、全文検索の条件を含めることが可能です。
Containsの中に検索キーワードをセットして下さい。
EQLを利用し検索する場合は、当該Entityに対して設定されているセキュリティ権限が反映されます。Containsの中に検索キーワードをセットして下さい。
EntityManager em = ManagerLocator.manager(EntityManager.class); Query query = new Query(); query.select(Entity.OID, Entity.NAME).from("search.Test01").where(new Contains("hogehoge")); SearchResult<Entity> result = em.searchEntity(query);
もしくはEQL直接以下のように利用可能です。
EntityManager em = ManagerLocator.manager(EntityManager.class); SearchResult<Entity> result = em.searchEntity(Query.newQuery("select oid, name from search.Test01 where contains ('test')"));
-
-
-
検索結果および詳細などのView設定
全文検索結果に表示されるプロパティや[詳細、編集]リンク押下時の遷移先ViewをAdminConsoleから設定することが可能です。まず、対象のEntity毎に全文検索結果に表示したい項目などを設定したViewをSearch Layoutで作成してください。
その後、AdminConsole画面のMetaDataSettings内にあるView Components > TopView の設定を変更します。
※TopViewの機能概要、作成方法についてはTopViewの章を参照してください。右にあるメニューから、Toolbar Parts > Fulltext Search(PU) を選択し、Main Area(Droppable P(Parts))にドラックアンドドロップしてください。
ドラックアンドドロップして出てきたFulltext Searchの設定ボタンをクリックすると、「crawl for full text search」にチェックをつけたEntityのみが表示されます。
Entity View列に設定したSearchViewを使用して、全文検索結果となったEntityの情報を表示します。別途対象EntityのSearch ViewでカスタマイズしたViewを作成することで、Entity Viewの選択リストに表示されるようになります。 その他の設定可能な項目は以下になります。
設定項目 設定内容 Display search textbox
本項目にチェックを入れると、ヘッダーに全文検索用のテキストボックスが表示されます。
Entity View
全文検索の結果表示で利用するViewを選択します。
show in search list
本項目にチェックを入れると、全文検索実行時の対象として、個別に選択が可能になります。
-
詳細・編集リンクのカスタマイズ
全文検索結果を表示するSearchViewのSearchFormView Settingに自作したアクションを設定することで、カスタマイズした画面への遷移が可能となります。-
詳細リンク先アクション
-
編集リンク先アクション
遷移先で取得可能なリクエスト情報は以下の通りになります。
パラメータ名 内容説明 defName
選択した情報のEntity定義名
oid
選択した情報のOID
version
選択した情報のVersion
-