Splunk Search

What's your best Humans vs Zombies query?

Runals
Motivator

As a spin on the rabbit/coyote population cycle I've come up with one for humans vs zombies (somewhat at boss' request). Am curious if anyone has done the same or if anyone could come up with a better/more interesting model. This query currently

  • Randomly determines each hour which population (one or the other - not both) have a population decrease
  • Randomly determines the percentage of the population loss
  • if the humans lose then 40% become zombies
  • if the zombies lose then the human population grows by 10%

As the query has progressed I've accounted for a max human population not to exceed its original amount (at one point the earth had approx 10 trillion people), the zombie population will never go below 1, and population change % not to go over 85%.

Part of the 'issue' is dealing with zombie decay (if at all), how or what % of the human population is converted to zombies (ie old school bites or if you die then you become a zombie), how fast should the humans recover (if you dealt with 'real' numbers from a time perspective the humans would never recover). At some level it might be better to remove the global population from the equation and simply list different cities as a way to explain an influx of humans. One thing to note about the random function (or maybe how I'm using it) is that the random number for each line has always been either even or odd for the first line and the second line is the opposite. In other words I've never seen two evens or two odds. It can make the output a bit more interesting as at a global level the humans took a hit but at a local level they have made some gains.

At any rate to get this going simply create a csv named hvz along the following lines; change the cities to suit. Have the query populate to a summary index of choice.

city,pop_h,pop_z
Global,7000000000,1
Columbus,8000000,1

| inputlookup hvz.csv | eval change = random() | eval pop_change = if(change % 2 = 1, "h", "z") | eval change_perc = floor(2147483647/change) | eval change_perc = if(change_perc > 85, 85, change_perc) | eval pop_z_new = if(pop_change="z", pop_z * ((100 - change_perc)/100), pop_z) | eval pop_h_new = if(pop_change="h", pop_h * ((100 - change_perc)/100), pop_h) | eval pop_z_update = if(pop_change="h", (pop_h - pop_h_new) * .40 + pop_z, pop_z_new) | eval pop_h_update = if(pop_change="z", pop_h * 1.1, pop_h_new) | fields - pop_h pop_z change pop_h_new pop_z_new | eval pop_h_update = case(pop_h_update < 1, 1, city="Columbus" AND pop_h_update > 850000, 850000, city="Global" AND pop_h_update > 7000000000, 7000000000, 1=1, pop_h_update) | eval pop_z_update = case(pop_z_update < 1, 1, city="Columbus" AND pop_z_update > 800000, 800000, city="Global" AND pop_z_update > 7000000000, 7000000000, 1=1, pop_z_update) | rename pop_h_update as pop_h pop_z_update as pop_z | outputlookup hvz.csv

My dashboard is currently

<dashboard>
  <label>Humans vs Zombies</label>
  <row>
    <panel>
      <chart>
        <title>Global Population Percent</title>
        <searchString>index=summary source=hvz* city=global  | table _time pop_h pop_z | eval faction = "Human Zombie" | makemv faction | mvexpand faction | eval pop = if(faction="Human", pop_h, pop_z) | fields - pop_* | timechart max(pop) by faction</searchString>
        <earliestTime>-36h@h</earliestTime>
        <latestTime>now</latestTime>
        <option name="charting.axisLabelsX.majorLabelStyle.overflowMode">ellipsisNone</option>
        <option name="charting.axisLabelsX.majorLabelStyle.rotation">0</option>
        <option name="charting.axisTitleX.visibility">visible</option>
        <option name="charting.axisTitleY.visibility">visible</option>
        <option name="charting.axisTitleY2.visibility">visible</option>
        <option name="charting.axisX.scale">linear</option>
        <option name="charting.axisY.scale">linear</option>
        <option name="charting.axisY2.enabled">false</option>
        <option name="charting.axisY2.scale">inherit</option>
        <option name="charting.chart">area</option>
        <option name="charting.chart.nullValueMode">connect</option>
        <option name="charting.chart.sliceCollapsingThreshold">0.01</option>
        <option name="charting.chart.stackMode">stacked100</option>
        <option name="charting.chart.style">shiny</option>
        <option name="charting.drilldown">all</option>
        <option name="charting.layout.splitSeries">0</option>
        <option name="charting.legend.labelStyle.overflowMode">ellipsisMiddle</option>
        <option name="charting.legend.placement">right</option>
      </chart>
    </panel>
    <panel>
      <chart>
        <title>Global Population</title>
        <search>
          <query>index=summary source=hvz* city=global  | table _time pop_h pop_z | eval faction = "Human Zombie" | makemv faction | mvexpand faction | eval pop = if(faction="Human", pop_h, pop_z) | fields - pop_* | timechart span=20m max(pop) by faction</query>
          <earliest>-36h@h</earliest>
          <latest>now</latest>
        </search>
        <option name="charting.axisLabelsX.majorLabelStyle.overflowMode">ellipsisNone</option>
        <option name="charting.axisLabelsX.majorLabelStyle.rotation">0</option>
        <option name="charting.axisTitleX.visibility">visible</option>
        <option name="charting.axisTitleY.visibility">visible</option>
        <option name="charting.axisTitleY2.visibility">visible</option>
        <option name="charting.axisX.scale">linear</option>
        <option name="charting.axisY.scale">linear</option>
        <option name="charting.axisY2.enabled">false</option>
        <option name="charting.axisY2.scale">inherit</option>
        <option name="charting.chart">line</option>
        <option name="charting.chart.nullValueMode">gaps</option>
        <option name="charting.chart.sliceCollapsingThreshold">0.01</option>
        <option name="charting.chart.stackMode">default</option>
        <option name="charting.chart.style">shiny</option>
        <option name="charting.drilldown">all</option>
        <option name="charting.layout.splitSeries">0</option>
        <option name="charting.legend.labelStyle.overflowMode">ellipsisMiddle</option>
        <option name="charting.legend.placement">right</option>
        <option name="charting.chart.bubbleMaximumSize">50</option>
        <option name="charting.chart.bubbleMinimumSize">10</option>
        <option name="charting.chart.bubbleSizeBy">area</option>
      </chart>
    </panel>
  </row>
  <row>
    <panel>
      <chart>
        <title>Columbus Population</title>
        <search>
          <query>index=summary source=hvz* city=columbus  | table _time pop_h pop_z | eval faction = "Human Zombie" | makemv faction | mvexpand faction | eval pop = if(faction="Human", pop_h, pop_z) | fields - pop_* | timechart span=20m max(pop) by faction</query>
          <earliest>-36h@h</earliest>
          <latest>now</latest>
        </search>
        <option name="charting.axisLabelsX.majorLabelStyle.overflowMode">ellipsisNone</option>
        <option name="charting.axisLabelsX.majorLabelStyle.rotation">0</option>
        <option name="charting.axisTitleX.visibility">visible</option>
        <option name="charting.axisTitleY.visibility">visible</option>
        <option name="charting.axisTitleY2.visibility">visible</option>
        <option name="charting.axisX.scale">linear</option>
        <option name="charting.axisY.scale">linear</option>
        <option name="charting.axisY2.enabled">false</option>
        <option name="charting.axisY2.scale">inherit</option>
        <option name="charting.chart">bar</option>
        <option name="charting.chart.nullValueMode">gaps</option>
        <option name="charting.chart.sliceCollapsingThreshold">0.01</option>
        <option name="charting.chart.stackMode">stacked</option>
        <option name="charting.chart.style">shiny</option>
        <option name="charting.drilldown">all</option>
        <option name="charting.layout.splitSeries">0</option>
        <option name="charting.legend.labelStyle.overflowMode">ellipsisMiddle</option>
        <option name="charting.legend.placement">right</option>
        <option name="charting.chart.bubbleMaximumSize">50</option>
        <option name="charting.chart.bubbleMinimumSize">10</option>
        <option name="charting.chart.bubbleSizeBy">area</option>
      </chart>
    </panel>
    <panel>
      <chart>
        <title>Columbus - Current Population</title>
        <search>
          <query>index=summary source=hvz* city=columbus | dedup city | table _time pop_h pop_z | eval faction = "Human Zombie" | makemv faction | mvexpand faction | eval pop = if(faction="Human", pop_h, pop_z) | fields - pop_* | stats max(pop) by faction</query>
          <earliest>-2h@h</earliest>
          <latest>now</latest>
        </search>
        <option name="charting.axisLabelsX.majorLabelStyle.overflowMode">ellipsisNone</option>
        <option name="charting.axisLabelsX.majorLabelStyle.rotation">0</option>
        <option name="charting.axisTitleX.visibility">visible</option>
        <option name="charting.axisTitleY.visibility">visible</option>
        <option name="charting.axisTitleY2.visibility">visible</option>
        <option name="charting.axisX.scale">linear</option>
        <option name="charting.axisY.scale">linear</option>
        <option name="charting.axisY2.enabled">false</option>
        <option name="charting.axisY2.scale">inherit</option>
        <option name="charting.chart">pie</option>
        <option name="charting.chart.nullValueMode">connect</option>
        <option name="charting.chart.sliceCollapsingThreshold">0.01</option>
        <option name="charting.chart.stackMode">stacked100</option>
        <option name="charting.chart.style">shiny</option>
        <option name="charting.drilldown">all</option>
        <option name="charting.layout.splitSeries">0</option>
        <option name="charting.legend.labelStyle.overflowMode">ellipsisMiddle</option>
        <option name="charting.legend.placement">right</option>
        <option name="charting.chart.bubbleMaximumSize">50</option>
        <option name="charting.chart.bubbleMinimumSize">10</option>
        <option name="charting.chart.bubbleSizeBy">area</option>
      </chart>
    </panel>
  </row>
</dashboard>
Tags (4)

badarsebard
Communicator

So your model isn't just a spin on a predator/prey system, it is a predator/prey system. There are a number of models that describe predator/prey systems, but one of the most famous is the Lotka-Volterra equations. This is the typically the first model introduced to students studying these models (as well as introductory differential equations classes). The LV model has a few assumptions in order to be valid, but the assumptions fit surprisingly well for a human/zombie system. The assumptions are as follows:
The prey find ample food at all times (arguable, but we'll assume so thanks to modern food preservation methods).
The food supply of the predator population depends entirely on the size of the prey population (zombies only eat humans).
The rate of change of population is proportional to its size (pretty straight forward).
The environment does not change in favor of one species and genetic adaptation is inconsequential (model is static).
Predators have limitless appetite (hahahaha).

Now, given these assumptions we finally arrive at the LV equations:
dx/dt = ax - bxy
dy/dt = cxy - dy

Where x is the prey population, y is the predator population, t is time, and a,b,c,d are positive real parameters describing growth and decay of the two species. Specifically, a is the growth of the prey without predation (human birthrate), b is the decay of the prey during interaction with predators (death to humans rate), c is the growth of the predators while interacting with prey (human to zombie conversion rate), and d is the decay of the predators in the absence of predation (zombie starvation/discorporation). For those not familiar with differential equations, dx/dt and dy/dt is a fancy math way of saying the change of x and y over time.

The first big advantage of this model in describing the problem is that the change in population is deterministic, so there is no randomness to determine which population decreases, it is known on the onset. Also, the amount of change that occurs is deterministic as well, so no randomness there. So we can even establish some of these based on what you have above. First, prey growth rate is 10%, so a=.1 (remember, a is in an equation which measures the change, not the full pop). We also have that 40% of humans become zombies when fed upon, therefore c=.4b, because, as you recall, b is the decay rate of the prey. Now, we still need the natural decay rate of zombies, and the most critical part, predation rate of human/zombie interaction. Basically, how many humans die given a number of zombies. Just to get some numbers, we'll say 50%, so b=.5 and then a zombie decay rate of 20% so d=.2. If b=.5 then c=.4*.5=.2. So plugging into our equations we get:
dx/dt = .1x - .5xy
dy/dt = .2xy - .2y

Note: these numbers are probably way off from what they should be, but it's interesting to play around with the parameters and see what happens. In fact, the 50% is WAY off after I ran the numbers, but this just gives an idea.

So, now we incorporate this into the search. Since this all takes place (loosely) time based, we need a way to iterate. So what I do is use gentimes and map and create the following.

|gentimes start=1/1/07 end=12/31/07
| map search="|inputlookup hvz.csv
|eval pop_h_delta=(.05*pop_h)-(.000000001*pop_h*pop_z)
|eval pop_z_delta=(.1*.000000001*pop_h*pop_z)-(.2*pop_z)
|eval pop_h=pop_h+pop_h_delta
|eval pop_z=pop_z+pop_z_delta
|fields city,pop_h,pop_z
|outputlookup hvz.csv" maxsearches=365

This first creates a series of rows and then map applies the search string over each of the rows, by doing an input output at the beginning and end of the string we effectively loop over time. Try playing around with not only the parameters, but also the human/zombie starting populations. If you manipulate the numbers just right you can get the system into a nice equilibrium where neither population goes extinct and they oscillate nicely.

alacercogitatus
SplunkTrust
SplunkTrust

Is there a question to be answered?

0 Karma

martin_mueller
SplunkTrust
SplunkTrust

It's right in the title 😛

0 Karma

ChrisG
Splunk Employee
Splunk Employee

Defect in displaying XML is fixed, I updated so yours displays correctly.

Runals
Motivator

Great; thanks!

0 Karma

Runals
Motivator

How do you make a new tag on the board?

0 Karma

ChrisG
Splunk Employee
Splunk Employee

Not all users can add tags, I added some for you. I also tried to reformat your dashboard XML so it displayed correctly, but apparently there is a bug in the Answers platform and it just won't work. I have notified the Splunk community team and they are working on it.

0 Karma

Runals
Motivator

Thanks for updating the Answers team; I posted my stuffs w/o putting in as 'code' because of the format issue. When I tried to create a new tag I got an error saying the tag didn't exist and would wipe out what I attempted /shrug.

0 Karma
Get Updates on the Splunk Community!

Splunk Forwarders and Forced Time Based Load Balancing

Splunk customers use universal forwarders to collect and send data to Splunk. A universal forwarder can send ...

NEW! Log Views in Splunk Observability Dashboards Gives Context From a Single Page

Today, Splunk Observability releases log views, a new feature for users to add their logs data from Splunk Log ...

Last Chance to Submit Your Paper For BSides Splunk - Deadline is August 12th!

Hello everyone! Don't wait to submit - The deadline is August 12th! We have truly missed the community so ...