drools サンプルプログラム3

少し複雑な条件でのサンプルプログラム

  • プログラム概要
    • 車両保険の割引率計算のプログラムです。Factはサンプルプログラム2のものに、ゴールド免許か否か、利用用途加えたものになります。
	免許
		ゴールド免許
		+5%割引
	年齢
		18<=年齢<25		 0%
		25<=年齢<35		10%
		35<=年齢<50		13%
		50<=年齢		 5%
	利用目的
		30歳以上、40歳未満で
		日常・レジャー(近距離)の利用は+2%OFF
		通勤利用		0%

  • ファクト
    • 省略しますが、PurposeType,LicenseTypeはenumです。割引率をdiscountで定義しています。
public class Profile {

	private int age;

	private String name;
	
	private PurposeType purpose;
	
	private LicenseType licenseType;
	
	private int discount;

	public Profile(String name, int age, PurposeType purpose, LicenseType licenseType) {
		this.name = name;
		this.age = age;
		this.purpose=purpose;
		this.licenseType = licenseType;
	}

	public int getAge() {
		return age;
	}

	public String getName() {
		return name;
	}

	public PurposeType getPurpose() {
		return purpose;
	}

	public LicenseType getLicenseType() {
		return licenseType;
	}

	public void setDiscount(int discount) {
		this.discount = discount;
	}

	public int getDiscount() {
		return discount;
	}
}
  • 実行プログラム
    • 殆どさきほとど一緒です。
public class Discount {

	public static final void main(String[] args) {
		try {
			KnowledgeBase kbase = readKnowledgeBase();
			StatefulKnowledgeSession ksession = kbase
					.newStatefulKnowledgeSession();
			KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory
					.newFileLogger(ksession, "test");
			
			Profile uzr = new Profile("uzr",29,PurposeType.CLOSE,LicenseType.GOLD);
			ksession.insert(uzr);
			ksession.fireAllRules();
			
			System.out.println(uzr.getDiscount());
			
			logger.close();
			
		} catch (Throwable t) {
			t.printStackTrace();
		}
	}

	private static KnowledgeBase readKnowledgeBase() throws Exception {
		
		KnowledgeBuilder kbuilder = KnowledgeBuilderFactory
				.newKnowledgeBuilder();
		
		kbuilder.add(ResourceFactory.newClassPathResource("sample3/Discount.drl"),
				ResourceType.DRL);

		KnowledgeBuilderErrors errors = kbuilder.getErrors();
		if (errors.size() > 0) {
			for (KnowledgeBuilderError error : errors) {
				System.err.println(error);
			}
			throw new IllegalArgumentException("Could not parse knowledge.");
		}
		
		KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
		kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
		
		return kbase;
	}
}
  • ルール
    • 新たな試みが二つ。ひとつはデバッグ文出力のため、functionを利用しました。
    • もうひとつはno-loopです。たとえば、25歳以上で、ゴールド免許のデータがファクトとして入ってきた場合、ゴールド免許で評価されたあとに、25歳以上というルールでも評価され、またゴールド免許で・・・という風にループしてしまいます。これを防ぐのがno-loopです。一度評価されたものは再評価しません。
function void printDiscount(Profile p) {
    System.out.println(p.getName() + ":" + p.getDiscount());
}

rule "ゴールド免許割引"
    no-loop 
    when
        p:Profile(licenseType==LicenseType.GOLD)
    then
        p.setDiscount(p.getDiscount() + 5);
        printDiscount(p);
end

 
rule "年齢割引(25歳以上35歳未満は10%OFF)"
    no-loop 
    when
        p:Profile(age>=25,age<35)
    then
        p.setDiscount(p.getDiscount() + 10);
        printDiscount(p);
end

rule "年齢割引(35歳以上50歳未満は13%OFF)"
    no-loop 
    when
        p:Profile(age>=35,age<50)
    then
        p.setDiscount(p.getDiscount() + 13);
        printDiscount(p);
end

rule "年齢割引(50歳以上5%OFF)"
    no-loop 
    when
        p:Profile(age>=50)
    then
        p.setDiscount(p.getDiscount() + 5);
        printDiscount(p);
    end

rule "30歳-40歳で近距離利用は2%OFF"
    no-loop 
    when
        p:Profile(age>=30,age<40,purpose==PurposeType.CLOSE)
    then
        p.setDiscount(p.getDiscount() + 2);
        printDiscount(p);
end
  • 実行結果
uzr:10
uzr:15
15