Tuesday, June 13, 2006

retract ใน Drool

อ้างถึงที่เคย post เรื่อง drool ไป

โง่อยู่ตั้งนาน ไม่ยอมอ่านคู่มือให้ดี
feature หนึ่งใน Drool ที่ผมพลาดไปก็คือ
ก็คือ retract(object) ซึ่งตรงข้ามกับ assert(object)

assert ก็คือการส่ง object เข้าไปใน working memory ของ rule engine
ซึ่ง rule engine จะตรวจเงื่อนไขว่าควรจะมีการ trig ให้ rule อะไรทำงานบ้าง
ส่วน retract ก็ตรงกันข้าม ใช้สำหรับล้าง object ออกจาก working memory

ที่นี้ retract เอามาใช้ทำอะไรบ้าง
กรณีแรกเลย ก็คือ กรณีที่ rule conflict กัน
(assert ครั้งเดียว แล้วมีหลาย rule ที่ trig พร้อมๆกัน
และพยายาม update resource ตัวเดียวกัน)
ซึ่งเราต้องใช้ salience เข้ามาช่วย
เพื่อเรียงลำดับว่าอะไรมี priority สูงกว่ากัน

ที่ผมทำผิดไป ก็คือ ผมเรียงลำดับให้ rule ผิด
(ได้ผลลัพท์ถูก แต่ในแง่ของ performance แล้ว
ไม่ถูกต้องอย่างยิ่ง)
ที่ถูกต้อง คือต้องนำเอา retract มาช่วยตัดวงจรไม่ให้ rule ที่เหลือทำงาน
โดยเรียงให้ rule ที่มีความสำคัญสูงสุด มีค่า salience สูงสุด
และเมื่อ rule ทำงานเสร็จ ก็ให้ retract object ออกเสีย

rule "ทุกคนได้ส่วนลด 5%"
salience 0
when
o : Order()
then
o.setPercentDiscount(5.0);
retract(o);
end

rule "ลูกค้าภาคเหนือได้ส่วนลด 7 %"
salience 80
when
c : Customer(region == Customer.NORTH)
o : Order(customer == c)
then
o.setPercentDiscount(7.0);
retract(o);
retract(c);
end

rule "ซื้อเกิน 1500 บาท ด้วยเงินสด ได้ส่วนลด 10 %"
salience 90
when
o : Order(amount >= 1500, payType == Order.CASH)
then
o.setPercentDiscount(10.0);
retract(o);
end

rule "สินค้า p-1 จะไม่ให้ส่วนลด"
when
item : OrderItem(p : product)
eval(p.getProductCode().equals("p-1"))
then
item.setIncludeInTotalDiscount(false);
retract(item);
end


ลำดับของการ assert ก็ต้องเรียงให้ดีด้วย
ไม่งั้น retract อาจจะทำให้ case บาง case ไม่ fire ได้
for (OrderItem item : order.getItems()) {
workingMemory.assertObject(item);
}
workingMemory.assertObject(order.getCustomer());
workingMemory.assertObject(order);

Related link from Roti

No comments: