Let's say you're building a social web app where an aggregate root (f.e. BlogPost) could be liked and unliked. Now consider a malicious user who wrote a script to perform an endless amount of like and unlike on the same aggregate, maybe he hijacked multiple user accounts to do it in parallel. This would mean the aggregate would require lots of events in order to be rebuilt and the event log would contain thousands of useless events that are once collapsed only projecting one state change. Is there some pattern in EventSourcing to collapse those events with their respective anti-event in order to reduce the amount of data?
Typically, you would handle this sort of thing in the application, rather than in the domain. For example, a rate limiter to restrict the number of edits per BlogPost, maybe another on the edit command itself. This sort of thing comes up in authentication security, so you might look there.
A second approach would be to treat up or down votes as events, rather than commands. These are external events that your application subscribes to, just as though it were listening to events emitted by a different domain model. A downstream process manager subscribes to the events, and dispatches commands to your model in response.
The advantage here is that it makes sense to treat the events as a batch; rather than passing through every event that you see, you can filter out any events that cancel out before passing them through for processing. You could use throttling here as well (again, these aren't your model's events, so you don't need to worry about re-hydrating state from them; you only use your own events to rebuild state).
If those don't work for your circumstances, you could also consider loading your state from snapshots (you still have the enormously long event history, but it doesn't matter because those events have been collapsed behind the recent snapshot).
Another alternative is to simply repair the event stream; elide the events generated by the attack, generate new sequence numbers for the rest, replace. If the problem is rare, and inexpensive to fix, it's perfectly reasonable for the business to decide that complicated solutions to prevent the problem are not a priority.
You can counter this problem and solve some others by 'snapshotting' your object.
When you do this you build an object to its current state via events and then save that state as the new first event. Discarding or moving to an archive events which occurred before the snapshot.
This enables you to limit the size of an object at the cost of losing its history.