hazelcast give another Cardinality Estimator object by unique name - hazelcast

I have a problem in getting cardinality service in hazelcast.
In following code, I add some visitor to cardinality estimator. messageID is unique. In test environment that filled by 5K unique item by this code.
public void AppendVisitor(String messageID, String visitor) {
CardinalityEstimator cs = this.hazelcast.getCardinalityEstimator(messageID);
cs.add(visitor);
this.viewsList.putIfAbsent(messageID, Long.valueOf(System.currentTimeMillis() / 1000L));
}
In expiration of viewsList in another class I write listener code. The entry event key was messageID in previous code. But when call this function, visit is 0. Seems it get another object that is empty.
#Override
public void entryEvicted(EntryEvent<String, Long> entryEvent) {
long visit = hazelcast.getCardinalityEstimator(messageID).estimate();
}

Related

Add an Address to the Branch

I am trying to add another address to a Branch in 21.203, similar to the how the DefAddress works. I have extended the Branch DAC and added the field to the extension. I also tried extending the BAccount DAC and table to get this to work but, nothing is working so far. The Address record is being created in the Address table but, the PXDBChildIdentity attribute doesn't seem to be sending back the ID to the Address record. On the screen, when I enter the values for the address, and click Save, all of the values are wiped out and the custom field (UsrCustomAddress) is never populated.
#region UsrCustomAddress
[PXDBInt()]
[PXUIField(DisplayName="Custom Address")]
[PXDBChildIdentity(typeof(Address.addressID))]
public virtual Int32? UsrCustomAddress { get; set; }
public abstract class usrCustomAddress : PX.Data.BQL.BqlInt.Field<usrCustomAddress> { }
#endregion
And, then, I added the View to the BranchMaint extension.
<code>
namespace PX.Objects.CS
{
public class BranchMaint_Extension : PXGraphExtension<BranchMaint>
{
public PXSelect<Address, Where<Address.bAccountID, Equal<Current<BAccount.bAccountID>>,
And<Address.addressID, Equal<Current<BAccountExt.usrCustomAddress>>>>> CustomAddress;
}
}
</code>
Not sure what I'm missing?
TIA!
I handled this by manually calling .Insert() on the specific Data View in the row inserting event and writing it to the field. PXDBChildIdentity then can update the field with the real identity value (on row persist) after the link is established.
protected void _(Events.RowInserting<Branch> e)
{
if (e.Row is null) return;
Address newAddress = CustomAddress.Insert();
BranchExt ext = e.Cache.GetExtension<BranchExt >(e.Row);
ext.UsrCustomAddress = newAddress.AddressID;
}
If anyone knows how to do this in an attribute id love to know. Note, this will only work for newly created records. Any existing records would not have a row inserting event fire and fill your custom field. You need to backfill the data with SQL or just a temporary custom action that you can invoke this code manually.

Add note to custom data record in code

I was searching for a solution to add a note to a database row I am creating in a custom table. I found the solution below from Ruslan for accessing the noteid, but I don't understand how this would be used to add a note to the row. I have all the code to create the row, I just need the attributes or function call to actually attach the text of the note to the row.
==================================================================
To have Note record automatically created when a new parent record gets saved, one should invoke the static PXNoteAttribute.GetNoteID(PXCache cache, object data) method when the parent record is inserted in the cache.
For example, to have Note record automatically created when a new Stock Item gets saved, you should subscribe to RowInserted handler for the InventoryItem DAC and call PXNoteAttribute.GetNoteID(...):
public class InventoryItemMaintExt : PXGraphExtension<InventoryItemMaint>
{
public void InventoryItem_RowInserted(PXCache sender, PXRowInsertedEventArgs e)
{
var noteCache = Base.Caches[typeof(Note)];
var oldDirty = noteCache.IsDirty;
PXNoteAttribute.GetNoteID<InventoryItem.noteID>(sender, e.Row);
noteCache.IsDirty = oldDirty;
}
}
The code snippet above can be incorporated into almost any custom BLC with a couple simple changes to replace InventoryItem with a custom DAC.
After implementing Gabriel's suggestions:
I do not seem to get any note in the database. The code compiles and runs fine, but the notes are not generated as far as I can tell. The note id is set in my table, but no data appears in the note table. Please take a look at my code and let me know what needs to change. Also, how do I get the note column into a grid, or does it automatically become available when it is done correctly?
Database field definition:
[NoteID] [uniqueidentifier] NULL
DAC field:
#region NoteID
public abstract class noteID : PX.Data.IBqlField
{
}
protected Guid? _NoteID;
[PXNote()]
public virtual Guid? NoteID
{
get
{
return this._NoteID;
}
set
{
this._NoteID = value;
}
}
#endregion
Code to create record:
private static bool acumaticaException(Exception e, EDImportExceptionMaint excpMaint, LingoRet850 res850)
{
excpMaint.Clear();
var except = new EDImportExcept();
except.ExceptReason = "U";
except.Active = true;
<...field assignments...>
except.OrderNbr = "";
PXNoteAttribute.SetNote(excpMaint.Exception.Cache, excpMaint.Exception.Current,
((PX.Data.PXOuterException)e).InnerMessages[0] + "-" + e.Message);
excpMaint.Exception.Insert(except);
excpMaint.Actions.PressSave();
return true;
}
To set the note of a record, use the SetNote()static function of PXNoteAttribute
PXNoteAttribute.SetNote(Base.Item.Cache, Base.Item.Current, "Hello, World!");
Calling SetNote will also take care of adding the Note record if it doesn't exist, so you don't have to call GetNoteID before setting the note value as in your question.
P.S. There is also a GetNote function which allows you to retrieve the current value of the note:
string note = PXNoteAttribute.GetNote(Base.Item.Cache, Base.Item.Current);

EntryProcessor without locking entries

In my application, I'm trying to process data in IMap, the scenario is as follows:
application recieves request (REST for example) with set of keys to be processed
application processes entries with given key and returns result - map where key is original key of the entry and result is calculated
for this scenario IMap.executeOnKeys is almost perfect, with one problem - the entry is locked while being processed - and really it hurts thruput. The IMap is populated on startup and never modified.
Is it possible to process entries without locking them? If possible without sending entries to another node and without causing network overhead (sending 1000 tasks to single node in for-loop)
Here is reference implementation to demonstrate what I'm trying to achieve:
public class Main {
public static void main(String[] args) throws Exception {
HazelcastInstance instance = Hazelcast.newHazelcastInstance();
IMap<String, String> map = instance.getMap("the-map");
// populated once on startup, never modified
for (int i = 1; i <= 10; i++) {
map.put("key-" + i, "value-" + i);
}
Set<String> keys = new HashSet<>();
keys.add("key-1"); // every requst may have different key set, they may overlap
System.out.println(" ---- processing ----");
ForkJoinPool pool = new ForkJoinPool();
// to simulate parallel requests on the same entry
pool.execute(() -> map.executeOnKeys(keys, new MyEntryProcessor("first")));
pool.execute(() -> map.executeOnKeys(keys, new MyEntryProcessor("second")));
System.out.println(" ---- pool is waiting ----");
pool.shutdown();
pool.awaitTermination(5, TimeUnit.MINUTES);
System.out.println(" ------ DONE -------");
}
static class MyEntryProcessor implements EntryProcessor<String, String> {
private String name;
MyEntryProcessor(String name) {
this.name = name;
}
#Override
public Object process(Map.Entry<String, String> entry) {
System.out.println(name + " is processing " + entry);
return calculate(entry); // may take some time, doesn't modify entry
}
#Override
public EntryBackupProcessor<String, String> getBackupProcessor() {
return null;
}
}
}
Thanks in advance
In executeOnKeys the entries are not locked. Maybe you mean that the processing happens on partitionThreads, so that there may be no other processing for the particular key? Anyhow, here's the solution:
Your EntryProcessor should implement:
Offloadable interface -> this means that the partition-thread will be used only for reading the value. The calculation will be done in the offloading thread-pool.
ReadOnly interface -> in this case the EP won't hop on the partition-thread again to save the modification you might have done in the entry. Since your EP does not modify entries, this will increase the performance.

Spring + ibatis + String matching

I have a Spring application integrated with ibatis.
I am calling some third party application from where I am getting a String message (a message is combination of messages, there are Strings concatenated with \ delimiter to concatenate the different messages from the third party) as output.
I have to filter this output based on String matching. There are some 150 other Strings. If the output message contains any string out of 150 messages, i have to add some functionality.
I need suggestions to implement it. I am thinking to put 150 Strings in table as the count may increase in future. The Output may contain either no message out of this 150, or any number of combinations with these 150 messages.
I am new to Spring. please tell me how to get these messages from database, since i do not have an id to fetch them or shall I get all of them as list and then compare the output string from the third party. Also please tell me If it wise to keep these messages in database or I can keep them in some property file as well, which one will be better in performance.
Thanks in advance.
Ok, let's start with some possibilities:
IF you will only be adding a few messages in the future and only do so with new releases, then storing the messages in an enum would be a viable choice:
enum ErrorMessage {
SOME_MESSAGE("something, bla bla"),
SOME_OTHER_MESSAGE("something_else"),
...;
private String message;
private ErrorMessage(String message) {
this.message = message;
}
public static ErrorMessage getByErrorMessage(String message) {
for(ErrorMessage errorMessage: message) {
if (errorMessage.message.equals(message)) {
return errorMessage;
}
}
return null;
}
public static boolean exists(String message) {
return getByErrorMessage(message) != null;
}
}
Please note that this version is quite primitive and could be improved by adding all the messages into a static Set:
static Set<String> messagesCache = new Hashset<String>();
//in constructor:
messagesCache.add( message );
// better exists() method:
public static boolean exists(String message) {
return messagesCache.contains(message);
}
Or, as with other solutions, you could only store the actual hashcode of your strings. A hashcode is simple a numeric representation of your string and will be unique enough for you to identify it. Same solution as above:
static Set<String> messagesHashCodes = new Hashset<String>();
//in constructor:
messagesHashCodes .add( message.hashCode() );
// better exists() method:
public static boolean exists(String message) {
return messagesHashCodes .contains(message.hashCode());
}
(Of course, it would be a good idea to check for null values, etc.)
The enum version has one big advantage, if you want to have DIFFERENT actions taken for some of the actions, you can code them into the enum, for example...
SOME_MESSAGE_REQUIRING_AN_ACTION("...") {
#Override
public void doAction(StringBuilder finalString) {
...doSomething.
}
}
...
public void doAction(StringBuilder finalString) {
finalString.append( this.message );
finalString.append( SOME_SEPERATOR );
}
public void static doAction(StringBuilder builder, String errorMessage) {
if (exists(errorMessage)) {
}
}
In this example, you CAN override the doAction method in each enum value, if it should do more/something else than append the message to the StringBuilder. It would also be a nice touch to add some "NULL_MESSAGE" to the enum List that does nothing and is only there to allow easier handling:
UNKNOWN_MESSAGE(null) {
#Override
public void doAction(StringBuilder finalString) {
// do nothing here
}
}
public static ErrorMessage getByErrorMessage(String message) {
for(ErrorMessage errorMessage: message) {
if (errorMessage.message != null && errorMessage.message.equals(message)) {
return errorMessage;
}
}
return UNKNOWN_MESSAGE;
}
This way, you can simple give every single string into your enum method doAction(StringBuilder, String) and get the result: If a message fits, it is added (and some other action taken), if not, it will be ignored, null checks included.
On the other hand, if you messages change quite often, then you might not do a release for such a change but keep the values in a database. In this case, I would use the hashCode() of the message as an id (as I said, unique enough, typically) and load the whole thing into memory when the application starts, allowing you, for example, to build again a Set of hashcodes to compare your errorMessages' hashcodes against.
protected void init() {
// load all error Messages from the database
// put them into a Map<String, String> (hashCode -> Value) or even just a Set<String> (hashcodes)
}

Am I writing duplicate domain logics when synchronise query database in CQRS and EventSourcing?

I'm confused with how to synchronise data to the query database.
Let's say I have an aggregate: CreditAccount and some commands may produce CreditAccountBalanceChangedEvent:
public class CreditAccount extends AbstractAnnotatedAggregateRoot<Long> {
#AggregateIdentifier
private Long id;
private int balance;
private DateRange effectiveDateRange;
#CommandHandler
public CreditAccount(CreateCreditAccountCommand command) {
apply(new CreditAccountCreatedEvent(command.getAccountId(),
command.getEffectiveDateRange()));
apply(new CreditAccountBalanceChangedEvent(command.getAccountId(),
command.getAmount()));
}
#EventHandler
private void on(CreditAccountCreatedEvent event) {
this.id = event.getAccountId();
this.effectiveDateRange = event.getEffectiveDateRange();
}
#EventHandler
private void on(CreditAccountBalanceChangedEvent event) {
//notice this line, some domain logic here
this.balance = add(this.balance, event.getAmount());
}
private int add(int current, int amount) {
return current + amount;
}
}
public class CreditAccountBalanceChangedEvent {
private final long accountId;
private final int amount;
//omitted constructors and getters
}
And everything works fine on the command handler side. And I set off to the query side but I find I'm writing some duplicate domain logic here:
#Transactional
#Slf4j
public class CreditAccountEventHandler {
private CreditAccountReadModelStore creditAccountReadModelStore;
#EventHandler
public void handle(CreditAccountCreatedEvent event) {
log.info("Received " + event);
creditAccountReadModelStore.store(accountDevriveFrom(event));
}
#EventHandler
public void handle(CreditAccountBalanceChangedEvent event) {
log.info("Received " + event);
final CreditAccountReadModel account = creditAccountReadModelStore
.findBy(event.getAccountId());
//notice this line, some domain logic here
account.setBalance(account.getBalance() + event.getAmount());
creditAccountReadModelStore.store(account);
}
//omitted setters and private methods
}
As you may notice, I wrote balance calculation code on both command and query side. My question is that is this inevitable in some situations or I write domain logic in wrong place?
As my study so far, events represent something have occured, so no business logic in them, they're just data holder(but reveal users's intent). So should I add a 'balance' field to CreditAccountBalanceChangedEvent and move balance calculation code to command handler method?
public class CreditAccount extends AbstractAnnotatedAggregateRoot<Long> {
//omitted fields
#CommandHandler
public CreditAccount(CreateCreditAccountCommand command) {
apply(new CreditAccountCreatedEvent(command.getAccountId(),
command.getEffectiveDateRange()));
apply(new CreditAccountBalanceChangedEvent(command.getAccountId(),
command.getAmount(), add(this.balance, command.getAmount())));
}
#EventHandler
private void on(CreditAccountBalanceChangedEvent event) {
//notice this line, some domain logic here
//event.getAmount() is no use here, just for auditing?
this.balance = event.getBalance();
}
}
In this case, I can remove balance calculation on the query side by using event.getBalance().
Sorry for a screen full question, any idea is appreciate.
I see two options.
One is for the command to contain the change in balance, the command handler to calculate the new balance, and the event to contain the new balance. If nothing is recalculated in the event handler, it ensures that if the business rules change in the future, they do not affect your object's history when when it is reconstituted from the events.
An alternative would be to place the business rules in a separate class that is called from both the command handler and the event handler to avoid duplication, and then to version those business rules -- via subclassing for example. So you could have an abstract class called CalculateBalanceRule with a subclass of CalculateBalanceRuleVersion1 that is initially referenced by both. If the rule changes, you create CalculateBalanceRuleVersion2, change your command handler to reference it, but keep the reference to Version1 in your event handler, so that it will always replay the rules it did originally.
The second approach is definitely more maintenance, but can answer HOW something change, not simply WHAT changed, if that's something that's important to your business.
Edit: A third option is for the event to only contain the new balance like in the first option, but to version the events. So you have BalanceChangedEvent, BalanceChangedEvent_v2, and so on. This is the direction I could take, as I don't really care to keep a history of how things changed, but I do need to account for the possibility that the events themselves might take on additional members or rename its members. Logic is then needed to determine which event version to use to reconstitute the object at each step.

Resources