**Contents**


### *Editorial* **Edge Computing for Internet of Things**

**Kevin Lee 1,\* and Ka Lok Man 2**


#### **1. Introduction**

The Internet of Things (IoT) is maturing and becoming an established and vital technology. IoT devices are being deployed in homes, workplaces and public areas at an increasingly rapid rate. IoT is the core technology of smart homes, smart cities, intelligent transport systems and automated logistics systems. IoT has the potential to optimize travel, improve logistics, reduce energy usage and improve quality of life.

With the increasing use of IoT, the problem of managing the vast volumes of data, wide variety and type of data that are generated, and erratic generation patterns is becoming increasingly clear and challenging. As well as the increasing number of IoT devices conducting traditional sensing, generating more data, there is also an increasing number of cameras, generating large volumes of complex data with stringent processing requirements. The current standard IoT model with Cloud computing is not sustainable, and a new model is needed to improve response time, reduce data transfer and increase processing availability.

This Special Issue is focused on solving this problem through the use of edge computing. Edge computing offers a solution to managing IoT data by processing IoT data close to the location where the data are generated. Edge computing allows for computation to be performed locally, thus reducing the volume of data that need to be transmitted to remote data centers and Cloud storage. It also allows for decisions to be made locally without having to wait for Cloud servers to respond.

#### **2. This Issue**

The ten articles in this Issue all present research in the area of edge computing for IoT. They address topics in the areas of resource management and offloading, deployment management, failure recovery, architectures, and algorithms for processing IoT data.

With the increasingly complex demands from IoT applications regarding end nodes and edge computing, there is an increasing need to effectively utilize the available resources. In [1], the authors focus on maximizing the use of available IoT devices by allowing them to collectively execute services using their spare resources. This reduces latency and data transfer to cloud services and improves the overall performance of IoT applications. Offloading computation is needed when the resources for a particular device are not enough to perform a task. In [2], the authors propose a new cooperative offloading method which uses edge-computing resources in rapidly changing environments. In this way, the authors aim to reduce latency and energy use. IoT applications should use all available resources, but it is difficult to decide which computation should run on which available resource. In [3] the authors examine approaches to job scheduling and execution on smart phones, with the goal of enabling the widespread use of dew computing. In [4], the authors aim to use Fog resources efficiently by utilising deep-learning to optimize content caching in edge nodes.

Edge-based IoT deployments need to be managed effectively, efficiently and automatically. IoT applications that involve end-nodes, edge and fog computing are complex to

**Citation:** Lee, K.; Man, K.L. Edge Computing for Internet of Things. *Electronics* **2022**, *11*, 1239. https://doi.org/10.3390/ electronics11081239

Received: 8 April 2022 Accepted: 12 April 2022 Published: 14 April 2022

**Publisher's Note:** MDPI stays neutral with regard to jurisdictional claims in published maps and institutional affiliations.

**Copyright:** © 2022 by the authors. Licensee MDPI, Basel, Switzerland. This article is an open access article distributed under the terms and conditions of the Creative Commons Attribution (CC BY) license (https:// creativecommons.org/licenses/by/ 4.0/).

manage. In [5], the authors propose a method for dynamically orchestrating services in a Fog architecture. The approach focuses on heterogeneous devices and the dynamic nature of the end devices. The appropriate placing of these edge resources is the focus of [6], which attempts to use reinforcement learning to optimize placement based on the latency and load of the server. The authors analyze the effectiveness of the proposed solution to attempt to maximize network-wide performance and focus on improving security using this approach.

The issue of automatically detecting and recovering from failures in container-based IoT deployment is the focus of paper [7]. The authors observe the rate at which data are received form the IoT end node, and if this is not as expected, perform the recovery process. The work is focused on container-based deployments, which are increasingly becoming the norm for IoT applications.

For edge computing to work effectively, system architectures that can be deployed in different contexts are needed. One such context is in automated warehouses, to support efficient logistics. In [8], the authors propose a hierarchical edge-based architecture to enable a rapid response in intelligent warehouses. The aim is to take advantage of edge nodes, to offer low latency while also enhancing the reconfiguration abilities of nodes at the edge of the network.

IoT data vary depending on their deployment and application; all data need to be processed in some way. In [9], the authors propose algorithms for processing spacial data that are of interest to the data mining field. They propose region-based frequent pattern growth (RFP-Growth) to search for associations in IoT data. In [10], the authors use deep learning algorithms to classify objects from RGB cameras on IoT end-devices.

**Acknowledgments:** We would like to thank all the authors who submitted their excellent work to this Special Issue. We are extremely grateful to all those reviewers who took the time to read and provide valuable feedback to authors regarding their submissions. The feedback from reviewers enabled authors to improve the overall quality of all the papers in this Special Issue. Our special thanks go to the editorial board of the MDPI Electronics journal for the opportunity to guest edit this Special Issue, and to the Electronics Editorial Office staff for their hard work ensuring an efficient peer-review schedule and timely publication.

**Conflicts of Interest:** The authors declare no conflict of interest.

#### **References**


**Jorge Coelho 1,2,\* and Luís Nogueira 1**


**Abstract:** Internet of things (IoT) devices play a crucial role in the design of state-of-the-art infrastructures, with an increasing demand to support more complex services and applications. However, IoT devices are known for having limited computational capacities. Traditional approaches used to offload applications to the cloud to ease the burden on end-user devices, at the expense of a greater latency and increased network traffic. Our goal is to optimize the use of IoT devices, particularly those being underutilized. In this paper, we propose a pragmatic solution, built upon the Erlang programming language, that allows a group of IoT devices to collectively execute services, using their spare resources with minimal interference, and achieving a level of performance that otherwise would not be met by individual execution.

**Keywords:** edge computing; computational offloading; orchestration; IoT; functional programming

#### **1. Introduction**

Given the ubiquity of internet of things (IoT) devices and their strong proliferation [1] many opportunities appear in exploring their potentialities, namely their connectivity and computational power [2]. It is well known that the quantity of data produced by a variety of data sources and sent to end systems to further processing is growing significantly, increasingly demanding more processing power. The challenges become even more critical when a coordinated content analysis of the data sent from multiple sources is necessary. Thus, with a potentially unbounded amount of stream data and limited resources, some of the processing tasks may not be satisfyingly answered by individual devices, guaranteeing a desired level of performance.

Computation offloading is recognized as a promising solution by migrating a part or an entire application to a remote server in order to be executed there. Various models and frameworks have been proposed to offload resource-intensive components of applications for more efficient execution [3–5]. However, these solutions rely on the concept of offloading to the cloud. Due to the increasing hardware capabilities of IoT devices and their proliferation, making it common to have several of these devices in the same area, offloading to the cloud may not always be a necessity, if the available resources of these devices are wisely used. The study of scenarios where heterogeneous nodes with unknown resources are aggregated in a collaborative effort to achieve some goal has been the subject of works such as [6] where some sort of data analysis is needed to estimate each node capacity and distribute work wisely.

Orchestration in distributed systems is a common approach to creating an abstraction layer between the several devices of the system. With the orchestration layer, devices that constitute the distributed system are "hidden" and their details and behavior are managed by the orchestrator (also referred as coordinator), providing a simplified interface to those devices and centered in the use of their resources without the need to know other

**Citation:** Coelho, J.; Nogueira, L. Enabling Processing Power Scalability with Internet of Things (IoT) Clusters. *Electronics* **2022**, *11*, 81. https:// doi.org/10.3390/electronics11010081

Academic Editor: Akash Kumar

Received: 22 November 2021 Accepted: 24 December 2021 Published: 28 December 2021

**Publisher's Note:** MDPI stays neutral with regard to jurisdictional claims in published maps and institutional affiliations.

**Copyright:** © 2021 by the authors. Licensee MDPI, Basel, Switzerland. This article is an open access article distributed under the terms and conditions of the Creative Commons Attribution (CC BY) license (https:// creativecommons.org/licenses/by/ 4.0/).

operational details. This is particularly relevant in service-oriented architectures (SOA) [7] with obvious applications when using clusters of IoT devices [8].

At the same time, functional programming is an established approach to implement parallel and distributed systems [9]. The minimization of the need of a shared state enables code distribution and parallel processing that fosters the development of easily scalable systems. Due to the rise of multicore and distributed systems, functional programming spread its influence through many mainstream languages [10,11] and is used in major cloud infrastructures such as the AWS Lambda [12]. In particular, Erlang [13], due to its simplicity and strong support for fault-tolerant distributed programming, is seen as a promising language for IoT applications [14].

In this paper, we propose an Erlang-based framework for the parallel processing of tasks in a cluster of IoT devices. These devices are able to communicate and report their resource availability, accepting computational tasks for execution. The goal is to have one of the connected devices requesting the offloading of tasks and relying on a module that coordinates all the communication process and balances the scheduling of tasks based on their estimated computational cost and the device's computational power and availability.

Resource allocation is one of the most complex problems in large multi-processor and distributed systems, and in general it is considered NP-hard. Computation platforms now integrate hundreds to thousands of processing cores, running complex and dynamic applications that make it difficult to foresee the amount of load they can impose to those platforms. Elementary combinatorics provides us with evidence of the problem of scale. For a simple formulation of the problem of allocating jobs to processors (one-to-one allocation), one can see that the number of allocations grows with the factorial of the number of jobs and processors.

A static allocation decided before deployment, based on the (nearly) complete knowledge about the load and the platform, is no longer viable. In traditional embedded systems, the workload is usually allocated in terms of its worst-case behaviour, but static allocations that take such characterisation into account tend to produce under-utilized platforms. It is, then, evident that optimal resource allocation algorithms cannot cope with this type of problem, and that lightweight heuristic solutions are needed. A comprehensive survey of the kinds of resource allocation heuristics that can cover different levels of dynamicity, while coping with the scale and complexity of high-density many-core platforms, is available in [15].

To cope with dynamism, a dynamic approach to resource management is the most obvious choice, aiming to dynamically learn and react to changes to the load characteristics and to the underlying computing platform. Linux has a strong momentum in the embedded software industry and has, in the past years, become the prevalent choice of operating system for new platforms. A paradigm, based on resource reservation, can endow applications with timing and throughput guarantees, independently of the good or malicious behavior of other applications, and can be employed across all system resources, including processor cycles, communication bandwidth, disk bandwidth, and storage.

The work presented here is the enhancement of previous work by the same authors [16,17] and the remaining of this paper is organized as follows. In the next section, we introduce the system model with the formal definitions for the network, communication protocol and scheduling behavior along with details of the orchestration process. Then, we describe the implementation of our system, and finally, we evaluate the results and conclude the paper.

#### **2. System Model**

We now proceed with the description of our system model by introducing formal definitions along with several considerations about its behavior. It is important to note that it is the programmer's responsibility to identify decomposable problems that can be used in this scenario. In a high level perspective, our system integrates the following features:


**Mapping of results:** Final result computation and its return to the application.

We use an orchestrator-based approach in order to achieve this. The details will be clarified in the following sections. We now proceed with some definitions and further explanations.

**Definition 1** (Task)**.** *We define a task, t<sup>i</sup> , as a λ function. By its nature, it will have no side effects and can be executed in parallel with other λ functions.*

In the remaining of this paper we will use the term task and lambda function for describing the same unit of execution and we use the term IoT device and node with the same meaning.

A device that needs to offload tasks to others can rely on a cluster of IoT devices for accomplishing this goal. We now define a cluster, which is the set of nodes currently available, meaning they are currently accepting tasks to execute.

**Definition 2** (Cluster of IoT devices)**.** *Given an IoT device, we represent it by a node n<sup>i</sup> . A cluster has a number of nodes, which can be variable during the execution of a computationally intensive application and is defined as* S = {*n*1, . . . , *nk*}*, where k* ≥ 1 *and n<sup>i</sup>* ∈ S *is one of the nodes currently available. The nodes can enter and leave the cluster at any time, as a result, for example, of a power failure (in case of leaving) or a new device is turned on (in case of entering).*

A cluster of nodes can be ordered from the more powerful to the less powerful members by evaluating their capabilities in terms of processing power and memory. Our option was to adopt a pragmatic approach, by implementing a simple heuristic function that relates clock speed, available CPU, number of cores, available RAM and available battery life. Details on how we get this data are described in the implementation section. We now define the device performance index.

**Definition 3** (Device Performance Index)**.** *We define a function,* P*, that given a node, n<sup>i</sup> , its CPU speed, Csn<sup>i</sup> (measured in Ghz), the number of cores, Ccn<sup>i</sup> , the available CPU capacity, Can<sup>i</sup> (measured in a number between 0 and 1), the available RAM, Mn<sup>i</sup> (measured in Gigabytes), and the available battery, Bn<sup>i</sup> (measured in a number number between 0 and 1), returns the value* P(*ni*)*, which is a numerical estimate for n<sup>i</sup> performance based on the following formula:*

$$\mathcal{P} = \mathfrak{a} \ast (\mathbb{C}s\_{n\_i} \ast \mathbb{C}c\_{n\_i} \ast \mathbb{C}a\_{n\_i}) + \mathfrak{f} \ast M\_{n\_i} + \delta \ast B\_{n\_i}$$

This is an easily computed value that, even if it is a relatively rough approximation, is, nevertheless, enough to distinguish each node's execution capacity without the burden of online benchmarking. It is also the programmer's responsibility to define adequate values for *α*, *β* and *δ* to produce an adequate value for his/her application.

**Example 1.** *Given a node, n*0*, reporting the following data: Csn*<sup>0</sup> = 1.4*, Ccn*<sup>0</sup> = 4*, Can*<sup>0</sup> = 0.6*, Mn*<sup>0</sup> = 0.37 *and without battery information, and given α* = *β* = 0.5*, the application of the formula results in:*

$$\mathcal{P} = 0.5 \ast (1.4 \ast 4 \ast 0.37) + 0.5 \ast 0.6 = 1.336$$

**Example 2.** *Given a node n*<sup>1</sup> *reporting the following data: Csn*<sup>1</sup> = 1.5*, Ccn*<sup>1</sup> = 4*, Can*<sup>1</sup> = 0.15*, Mn*<sup>1</sup> = 0.54*, the application of the formula results in:*

$$\mathcal{P} = 0.5 \ast (1.5 \ast 4 \ast 0.54) + 0.5 \ast 0.15 = 1.695$$

Knowing each node's performance index, we now define how to decompose the problem in order to distribute it in a balanced manner.

**Definition 4** (Simple Problem Decomposition)**.** *Given a problem* D *and given a cluster of available nodes* S = {*n*1, . . . , *nk*}*, then the problem must be decomposable in k parts and defined as* D = {*d*1, . . . , *dk*} *such that each part's computational cost is proportional to the assigned device performance index.*

**Example 3.** *Given nodes n*0, . . . , *n*<sup>5</sup> *and a problem of summing 100,000 numbers, the calculated performance index, the percentage of the computational power each node represents and the assigned partition of the problem is presented in the following table:*


A strict decomposition can be a bad solution if the computational cost of processing data is unevenly distributed, since a small interval of data can be harder to process than a larger one. The approach we purpose includes the option to split the work in a bounded number of parts that are processed sequentially by the cluster of nodes. We now define the enhanced problem decomposition.

**Definition 5** (Enhanced Problem Decomposition)**.** *Given a problem,* D*, and given a cluster of available nodes,* S = {*n*1, . . . , *nk*} *, then the problem must be decomposable in n parts and defined as* D = {*D*1, . . . , *Dn*} *and for each D<sup>i</sup>* ∈ D*, it is possible to decompose it further into k parts and defined as D<sup>i</sup>* = {*di*<sup>1</sup> , . . . , *dik*}*, such that each part's computational cost is proportional to the assigned device performance index. Thus, given a node, n<sup>i</sup> , with a percentage of system power, p<sup>i</sup> , then the size of the part, D<sup>i</sup> , it will process is given by p<sup>i</sup>* ∗ *sizeo f*(*Di*)*.*

**Example 4.** *Given the Example 3, if we choose to have five partitions, then we get:*


*l-elements*

*Here, each node n<sup>i</sup> will process p<sup>i</sup>* ∗ *l elements of each D<sup>i</sup> corresponding to:*


Given the previous definitions we can now define the assigned problem.

**Definition 6** (Assigned Problem)**.** *Given a cluster of nodes* S = {*n*1, . . . , *nk*}*, where each node n<sup>i</sup> has a performance index,* P*<sup>i</sup> , and the problem,* D*, which is decomposed in k different parts, we define an assigned problem as a set of triples,* A*<sup>P</sup>* = {(*n*1,P1, *d*1). . . (*n<sup>k</sup>* ,P*<sup>k</sup>* , *d<sup>k</sup>* )}*.*

Communication between nodes is done using asynchronous message passing. There is a permanent link between the node requesting the work and the nodes executing that work. When this link is broken, it signals a loss of communication and the node is removed from the list of available ones.

**Definition 7** (Link set)**.** *Given a cluster of available nodes* S = {*n*1, . . . , *nk*} *we define* L = {*l*1, . . . , *lk*} *as the list of links to the nodes such that the connection to node n<sup>k</sup> is done by link l<sup>k</sup> .*

Failure during the execution of a task results in rescheduling the unfinished task to the closest available node in terms of performance index. More formally, we define task reassignment.

**Definition 8** (Task Reassignment)**.** *Given a cluster of nodes,* S = {*n*1, . . . , *nk*}*, where each node, n<sup>i</sup> , has a performance index,* P*<sup>i</sup> , the problem,* D*, decomposed in k different parts proportional to each of the nodes and the assigned problem* A*<sup>P</sup>* = {(*n*1,P1, *d*1). . .(*n<sup>k</sup>* ,P*<sup>k</sup>* , *d<sup>k</sup>* )}*. When a link, lj , assigned to a node, n<sup>j</sup> , such that* (*n<sup>j</sup>* ,P*<sup>j</sup>* , *dj*) ∈ A*<sup>P</sup> fails, then the task, d<sup>j</sup> , is reassigned to the node, nm, such that* (*nm*,P*m*, *dm*) ∈ A*<sup>P</sup>* \ (*n<sup>j</sup>* ,P*<sup>j</sup>* , *dj*) *and* P*<sup>m</sup>* ≥ P*<sup>n</sup> for any* (*nn*,P*n*, *dn*) ∈ A*<sup>P</sup>* \ (*n<sup>j</sup>* ,P*<sup>j</sup>* , *dj*)*.*

The orchestrator plays a central role in the system. It is responsible for the coordination of the different participants, dealing with the details of each device and providing the programmer with an API that abstracts the use of the distributed system. Thus, its main features are:


The orchestrator relies on the host that needs to offload work to other nodes. We now describe in more detail the concepts behind each of its features and other relevant details will be clarified in the implementation section.

Communication is done by message passing. All the different participants behave like actors [18]. All the messaging relies on the built-in features of the Erlang language that provide high-level approaches to message passing and code distribution, facilitating the whole process.

IoT devices can enter and leave the cluster at anytime. When they enter, they are available to accept tasks to execute. The node starts by sending a registration message to the orchestrator and, after acknowledgment, sends its score, which results from a performance index computation in the node. This will allow the orchestrator to rank that specific node within the cluster. Nodes can leave the cluster in two different scenarios: (i) when the orchestrator is shutdown; and (ii) when they stop, for example, due to power failure. In the first case, a message is sent from the orchestrator to the node, terminating the collaboration process. In the second one, the orchestrator detects the node's failure and removes it from the list of available nodes. Again, these features rely strongly on the built-in features of Erlang.

The API that the orchestrator provides accepts code and data, and returns the result of applying the code to the data. Its main goal is to distribute the data by node. It starts by splitting the data by the different nodes using their rank (given by the score obtained by the computed device performance index) to create partitions of data that each one will process. This is illustrated in Figure 1, where we have an input to the orchestrator consisting of code and data, it distributes the code by the different nodes {*N*1, *N*2, . . . , *Nn*} and data D = {*D*1, *D*2, . . . , *Dn*}, such that they can process it locally. For each *N<sup>i</sup>* , the size of *D<sup>i</sup>* varies accordingly with *N<sup>i</sup>* 's rank.

**Figure 1.** Orchestration process.

It is also the role of the orchestrator to provide fault-tolerance. Here, fault-tolerance consists in guaranteeing that all the data is processed. Since data is split among different nodes, failure in one or more than one node during execution results in losing the corresponding partial result. To guarantee the completion of the designated task, the orchestrator maintains a permanent link with each node in the cluster and detects any failure. In case of failure, the task given to that node is rescheduled for execution in the available node with highest performance index.

#### **3. Data and Code Distribution Algorithm**

We now present the core algorithms of this framework. Algorithm 1 describes how data is split and Algorithm 2 describes how data is distributed among the nodes. In Algorithm 1 we start by choosing from the simple problem decomposition of data (Definition 4) or the enhanced problem decomposition (Definition 5). In the first case, we split data by the number of available nodes proportionally to each node's performance index. On the other hand, if the enhanced problem decomposition is chosen, then an additional parameter (here described by the variable *k*) is provided, allowing a first split of the partition into *k* parts, then, for each of these parts, the data is split again, now in *p* parts (given *p*, the number of available nodes) with each of these parts with a size proportional to the nodes' performance indexes. This allows a more fine-grained distribution to the computational power of nodes with respect to the data being processed, which is particularly useful when the processing data has an uneven processing cost.

Having all the parts of data defined, we proceed with the distribution of the data and the supplied code for processing the data (described as F) by the different nodes as described in Algorithm 2. The result is then stored. In case of a node being unable to complete a task, which translates into a broken link, the associated data must be processed by another node. The approach we use is to give it to the available node with highest performance to minimize further delays. In the case of several nodes failing, the process is repeated and the data is queued to the best available node. The algorithm hides most of the low-level technicalities which will be further discussed in the following sections.

#### **Algorithm 1** Data Split

Let D := {*D*1, . . . , *Dp*} be the set of data which is divided in *p* parts. Let D′ := {} be an empty set of data pairs.

1: **if** Simple Problem Decomposition **then** 2: *p* := *n* and the size of partition *D<sup>i</sup>* is adjusted to be proportional to *p<sup>i</sup>* 3: D′ := D′ ∪ {(*D*1, *n*1), . . . ,(*Dp*, *np*)} 4: **end if** 5: **if** Enhanced Problem Decomposition **then** 6: A size *k* is provided, *p* := *k* and 7: **for** each *D<sup>j</sup>* ∈ D **do** 8: Split *D<sup>j</sup>* in {*dj*<sup>1</sup> , . . . , *djp*} where each *dji* is proportional to *p<sup>i</sup>* 9: D′ := D′ ∪ {(*dj*<sup>1</sup> , *n*1), . . . ,(*djp*, *np*)} 10: **end for** 11: **end if**

12: **return** D′

#### **Algorithm 2** Data Distribution

Let S := {*n*1, . . . , *nn*} be the set of available nodes in the cluster. Let L := {*l*1, . . . , *ln*} be the set of links to nodes in the cluster, where *l<sup>i</sup>* is the link to node *n<sup>i</sup>* Let S<sup>P</sup> := {(*n*1, *p*1), . . . ,(*nn*, *pn*)} be the set of pairs of available nodes in the cluster where each *n<sup>i</sup>* is the node name and *p<sup>i</sup>* is node's *i* performance index. Let D′ be the result of execution of the previous algorithm. Let F be a function to process data in D. Let R := {} be an empty set of results of processing data in D by function F. Let *Success* := *False*

.

.

.

```
while Success = False do
   while D′ has data do
       Remove (da, nb
                      ) from D′
       Submit data da for execution by nb with code F
   end while
   Wait until all nodes return a response and add them as a tuple (ni
                                                                        ,ri) to R, where
ri
  is the value returned by node ni
                                   .
   if failed links exist then
       Add unprocessed requests (da, nb
                                         ) as (da, nc) to D′
                                                           , where node b is replaced by
the best one available, c.
   else
       Success := True
   end if
end while
```
#### **4. Implementation**

Although the idea is to have a general purpose solution for IoT devices, at this moment, we decided to focus on a specific type of hardware/software to develop a proof of concept with all the properties we believe that are relevant in this domain. Our nodes are all singleboard computers, namely Raspberry Pi devices [19]. They all run a Linux distribution and an Erlang virtual machine.

Although single-board computers (SBC) are just one type of IoT device, they enjoy enormous popularity due to their high performance for their price range and the vast number of scenarios where they can be used [19,20]. It is possible to have several Raspberry Pi SBCs in the same area, each with a different purpose. With our framework we enable the optimization of devices that are, often, sitting idle.

#### *4.1. IoT Node Implementation*

The IoT node must have installed the Erlang VM to allow code transfer, execution and communication. Whenever an IoT device is available for collaboration, it searches for a registered orchestrator (in Erlang, registered processes are those that have a name associated with them) and uses the Erlang built-in instruction, *net*\_*adm* : *ping*( ′ *orchestrator*\_*name*′ ), to register with the orchestrator. On success, the ping will add the IoT device to the list of known neighbors in the orchestrator process. Then, the device will compute its performance index using *sysbench* (https://github.com/akopytov/sysbench, accessed on 22 November 2021) and Linux's integrated *acpitools* and sends it to to the orchestrator. This allows the orchestrator to rank the node. From here on, the node is ready to be used as part of the cluster.

The code deployed to a node is initially minimal and consists of a simple process that executes code as instructed by received messages and is described in Listing 1.

**Listing 1.** IoT node main code.

```
t a s k _ e x e c u t o r ( )−>
r e c ei v e
{ From , execu te ,Mod, Fun , Param } −>
From ! { B , E ,Mod: Fun ( Param ) } ,
t a s k _ e x e c u t o r ( ) ;
_ −>
t a s k _ e x e c u t o r ( )
end .
```
The function, *task*\_*executor*/0, waits for messages instructing the node to execute code (function *Fun* from module *Mod* with parameters *Param*) and the result of the execution is returned to the requesting node.

#### *4.2. Orchestrator Implementation*

The orchestrator is executed on the node that needs to offload data. This node, as all the others nodes that may form a cluster, runs an Erlang VM and the orchestrator is activated whenever it needs to offload work to others. After activation, the orchestrator is able to build a cluster of IoT devices and knows each one's performance score. Therefore, it can split tasks accordingly. In more detail, after knowing the list of available nodes S (nodes that successfully registered and sent their performance index), the first step is to create a ranked list. Given a list of nodes, S = {*n*1, . . . , *nn*}, they will be ordered in a list from the one with highest performance index to the one with lowest performance index. Their relative computational power will be used to compute the partition they must handle.

The orchestrator then proceeds with the transfer of code, C, and data, D, to nodes in the cluster. Erlang provides an easy way to do this. Given a module, *Mod*, on the device where the orchestrator is running, the Erlang instruction *c* : *nl*(*Mod*) will transfer it to the nodes in A. After this step, all the nodes have the same version of the code and data and know the partition they will work on, which is also sent by the orchestrator.

Please note that this approach may not escalate well when the problem being decomposed does not have an even distribution of work. It is also unable to split inter-dependent pieces of data. Nevertheless, these type of problems can also be handled by the orchestrator, but data will not be partitioned. Instead, all the application will be transferred to the node with the highest performance index.

After all the work has been distributed, the orchestrator waits for the results and handles failures. Waiting for results means it will wait for an answer from each node with the result of its particular execution. In case there is some failure, for example one node disconnects, it detects this because it relies on the underlying Erlang mechanism that generates a message whenever one element of S stops working. Thus, it is easy to know if one node stopped working and which part of the data it was processing. In this case, the orchestrator reschedules this exact execution to another node. The criteria implemented

is to wait until the end of the current execution and reschedule the uncompleted one to the highest ranked node.

The orchestrator node coordinates the offloading process and, typically, nodes can be both an orchestrator and a node executing tasks. The orchestrator Erlang function is succinctly described in Listing 2.

**Listing 2.** Orchestrator node main code.

```
o r c h e s t r a t o r (Mod, Fun , Da taSize , NPart ) −>
NodesLis t = i n i t i a l i z e _ c l u s t e r ( ) ,
c : nl (Mod) ,
Parts_Node = d i s t r i b u t e ( NodesList , Da taSize , NPart ) ,
R e s ul t s = e xecu te (Mod, Fun , Parts_Node ) ,
re sechedule ( Re sul t s , Parts_Node ) .
```
The function *orchestrator*/4 receives the name of the module, *Mod*, with the code and data that must be distributed, the main function processing the data, *Fun*, the size of the data being processed, *DataSize*, and the number of partitions, *NPart*, that should be used in the distribution of the work. Next, the function *initialize*\_*cluster*/0 finds nodes in the local network area that are able to collaborate (execute the slave function described before), and adds them to the *NodesList*, establishing a link. Code and data are then distributed to the available nodes with the Erlang builtin function *c* : *nl*/1 and *distribute*/3 determines which parts of the data partition must be processed by which nodes. In case *NPart* is one, the process is a simple problem decomposition, if *N part* > 1, then the process is an enhanced problem decomposition. The next step is to send the data for remote execution and gather all the results in the *Results* list. Finally, the function *resechedule*/2 compares the results obtained from nodes with the requests that were made. In case it detects unanswered requests (resulting from nodes failing during execution), tasks related with those requests are rescheduled to available nodes as described in the system model.

**Example 5.** *Given a module, primes, where a function, sum\_primes*(*B*, *E*, *List*)*, returns the sum of the prime numbers in the interval from B to E in List and given a list of 100,000 numbers, summing all the primes in the list can be done using the cluster of IoT devices available, by submitting the following instruction to the orchestrator:*

#### orchestrator:process(primes,sum\_primes,1000000,1)

By calling this function, all the features previously described are used to create a collaborative effort of handling the problem.

#### **5. Evaluation**

We carried several tests using a cluster of four devices connected wirelessly to the same WiFi router. These four IoT devices were in use with different main applications as described in Table 1.


To evaluate the benefits of our framework, we have developed a battery of tests based on data-decomposable problems. Since results are consistent among the several tests, here, we present one of them, consisting of counting prime numbers in the interval [1, 50,000].

The interval we use in this test is I = {1, . . . , 50, 000} with a total of 5133 prime numbers. Note that the primes are not evenly distributed in this interval and higher ones are considerably more difficult to find than lower ones. We started with one device and added devices to the cluster measuring the gain in performance. Since the problem is not easy to break in balanced partitions we use the enhanced problem decomposition solution and break it in several partitions (1, 5, 10 and 20). Each of the partitions is then split by the available nodes accordingly with their reported performance index. We choose the node *n*<sup>1</sup> to be the node running the orchestrator although it can also execute tasks. The calculation of the primes on I<sup>1</sup> took an average of 26.07 s. We don't get any advantage in using more than one partition with only one device since the implementation already uses multiple processes to optimize the use of the available cores of the device. The results of distributing data by the nodes are presented in Figure 2.

**Figure 2.** Distributing data by nodes.

Note that, if we add one device (*n*<sup>1</sup> and *n*2), even with only one partition, the time needed to compute all the primes decreases from an average of 26.07 s to an average of 24.43 s. The performance increases as we divide chunks of work by the devices. With five partitions, we achieve the best result of an average 16.67 s. The increase in the number of partitions is not alone a factor of enhancement in performance, since, the more partitions we have, the more messages we need to exchange. When using devices *n*1, *n*<sup>2</sup> and *n*3, the performance increases considerably, which seems normal since *n*<sup>3</sup> is a powerful node in this context. Adding node *n*<sup>4</sup> also further increases the cluster's performance. In Table 2, one can see the percentage of gain in terms of execution time when adding, one, two and three devices to the cluster. The advantage is evident, although the gain when adding three devices when compared to two devices is marginal. One thing we notice is that problems have, generally, an ideal number of devices in the cluster to get the better trade-off between the size of the problem and the cluster setup and communication overhead.

**Table 2.** Percentage of gain by adding devices.


In Figure 3 we present the graphic detailing the gain of having one device (no devices added to help), with one, two and three devices added. These values are the ones for the configuration with best performance in each of the scenarios.

**Figure 3.** Result of adding devices to *n*<sup>1</sup> .

We also experimented with failure in nodes and consequent rescheduling. The impact of such operation is highly dependent on the capacity of the node or of the nodes failing. Failing node *n*<sup>3</sup> has a considerable higher impact than failing node *n*2, due to their different capacity and thus the amount of work that is distributed to them. Nevertheless, with a small number of failures, the cooperative distributed computation still has a better performance when compared to the single problem solving solution. In terms of time needed for the execution we conclude that given a set of nodes {*n*1, . . . , *nk*}, the time, *X*, needed to decompose the service, the time, *Y*, to send code and data to a node, the time, *W*, to send the result back from a node and, *tn<sup>i</sup>* , the time that node *n<sup>i</sup>* needs to processes its block, the total time, T , needed for a distributed service execution can be determined by:

$$\mathcal{T} = X + k \ast Y + \sum\_{i=1}^{k} \frac{t\_{n\_i}}{k} + k \ast W$$

From a general perspective and focusing only in the framework we developed and not the problems it may solve, we are able to draw some conclusions about the scalability of our framework. The division of work is done in two different approaches, one using a simplified split of data based on the performance index of the available nodes, and another based on the split in a given number of partitions and again, the split of each partition given the number of available nodes and their performance index. Both operations have low complexity since they have no relation with the size of the data being processed. In terms of communication and message passing the number of messages needed to setup the framework are equal to the number of available nodes and the number of messages needed to send and receive data are twice the number of partitions assigned to each node. Thus, the complexity of the whole framework setup and distribution of data and code is low. In the case of the enhanced problems assignment and depending on the data being processed, there is a compromise between the number of partitions given to each node and the time of the execution of the code over the data. Sometimes, depending on the data it may be faster to have less partitions, avoiding the communication overhead. General complexity of distributed systems has been previously studied in research such as [21–23].

#### **6. Conclusions**

Even though IoT devices are becoming more powerful, the available local resources cannot cope with the increasing computational requirements of resource-intensive applications that can be offered to a large range of end-users. This has created a new opportunity for task offloading, where computationally intensive tasks need to be offloaded to more resource powerful devices. Naturally, cloud computing is a well-tested infrastructure that can facilitate the task offloading. However, cloud computing, as a centralized and distant infrastructure, creates significant communication delays that cannot satisfy the requirements of the emerging delay-sensitive applications.

To this end, in this paper we presented a cooperative framework for IoT devices based in Single Board Computers and the Erlang programming language. The goal is to maximize the collaborative power of these devices with a minimal setup and interference on their main functions. By distributing the computational load across a set of heterogeneous IoT nodes, a cooperative environment enables the execution of more complex and resourcedemanding services that otherwise would not be able to be executed on a stand-alone basis or would suffer from unacceptable performance. We intend to add more features to the framework and foresee the creation of a distributed solution for computation that uses available power of simple devices replacing larger systems.

**Author Contributions:** Conceptualization, J.C. and L.N.; methodology, J.C. and L.N.; software, J.C.; validation, L.N.; investigation, J.C. and L.N.; writing—original draft preparation, J.C.; writing review and editing, J.C. and L.N.; visualization, J.C. and L.N.; supervision, J.C.; project administration, J.C. and L.N.; funding acquisition, J.C. All authors have read and agreed to the published version of the manuscript.

**Funding:** This research was supported by the Artificial Intelligence and Computer Science Laboratory, University of Porto (LIACC), FCT/UID/CEC/0027/2020, funded by national funds through the FCT/MCTES (PIDDAC).

**Institutional Review Board Statement:** Not applicable.

**Informed Consent Statement:** Not applicable.

**Data Availability Statement:** Not applicable.

**Conflicts of Interest:** The authors declare no conflict of interest.

#### **References**


## *Article* **FP-Growth Algorithm for Discovering Region-Based Association Rule in the IoT Environment**

**Hong-Jun Jang 1 , Yeongwook Yang 2 , Ji Su Park <sup>1</sup> and Byoungwook Kim 3, \***


**\*** Correspondence: bwkim@dsu.ac.kr; Tel.: +82-61-330-3358

**Abstract:** With the development of the Internet of things (IoT), both types and amounts of spatial data collected from heterogeneous IoT devices are increasing. The increased spatial data are being actively utilized in the data mining field. The existing association rule mining algorithms find all items with high correlation in the entire data. Association rules that may appear differently for each region, however, may not be found when the association rules are searched for all data. In this paper, we propose region-based frequent pattern growth (RFP-Growth) to search for association rules by dense regions. First, RFP-Growth divides item transaction included position data into regions by a density-based clustering algorithm. Second, frequent pattern growth (FP-Growth) is performed for each transaction divided by region. The experimental results show that RFP-Growth discovers new association rules that the original FP-Growth cannot find in the whole data.

**Keywords:** FP-Growth algorithm; association rules; frequency pattern analysis

#### **1. Introduction**

With the rapid development of mobile devices and sensor technology, various forms and vast amounts of spatial data are being collected in the IoT environment [1]. As the amount of spatial data collected increases in the IoT, the demand for using spatial information is also increasing in fields where spatial information has not been utilized before [2]. However, many IoT applications require short response times and depend on devices with limited resources, so the application of existing data mining techniques is inefficient and limited [3–6]. Research on spatial data mining techniques to obtain knowledge specific to a region using the physical location information of the sensor from which data are collected, is being actively conducted.

Frequent pattern (FP) mining has been extensively studied in the field of data mining. Apriori algorithm has received a lot of attention in the field of data mining [7–9]. However, Apriori-based approaches have the disadvantage that they generate many candidate sets and are expensive due to frequent database scans. In order to overcome this drawback, many papers have proposed a new data structure that calculates frequency itemsets from a transactional database. One of the most popular of these data structures is the FP-Tree structure [10]. FP-Growth algorithm, which is a data mining technique based on FP-Tree, can discover a set of complete frequency patterns. FP-Tree is an extended prefix-tree structure to store important and quantitative information related to frequency patterns, avoiding the shortcomings of the Apriori-based approach. FP-Tree has the advantage of low tree construction cost by creating a tree with two scans of the entire database. Thus, FP-Growth algorithm is faster than the Apriori algorithm. FP-Tree requires two database scans and cannot be applied to a variable database because the frequency of occurrence of items must be obtained through a full database scan before constructing a tree. In order to overcome these disadvantages, many methods of generating frequency pattern trees

**Citation:** Jang, H.-J.; Yang, Y.; Park, J.S.; Kim, B. FP-Growth Algorithm for Discovering Region-Based Association Rule in the IoT Environment. *Electronics* **2021**, *10*, 3091. https://doi.org/10.3390/ electronics10243091

Academic Editors: Kevin Lee and Ka Lok Man

Received: 28 October 2021 Accepted: 7 December 2021 Published: 12 December 2021

**Publisher's Note:** MDPI stays neutral with regard to jurisdictional claims in published maps and institutional affiliations.

**Copyright:** © 2021 by the authors. Licensee MDPI, Basel, Switzerland. This article is an open access article distributed under the terms and conditions of the Creative Commons Attribution (CC BY) license (https:// creativecommons.org/licenses/by/ 4.0/).

have been studied. The FP-Stream [11] structure is proposed to apply the existing FP-Tree in the streaming database, and the COFI-tree [12], which allows the conditional tree to be generated to a minimum through pruning during tree generation, and DRFP-Tree [13,14] to use a database instead of memory, and CanTree [15], which constructs a tree using alphabetical specific criteria as a method to reduce database scans to obtain the number of occurrences of items in FP-Tree.

A representative example of association rule mining is market basket analysis [16]. However, in the existing market basket analysis, one transaction only has a list of purchased items, not a region for purchasing the items. Table 1 shows an example of the item purchase region added to the item transaction used in the existing market basket analysis. If the purchase region is not considered in the market basket analysis, the support of beer→diaper is 0.5 (5/10) and the confidence of beer→diaper is 0.5 (4/8). If minimum support and confidence are set higher than 0.5 in order to prevent the generation of massive association rules, beer→diaper will not be derived. → → →

**Table 1.** An example of item transaction considering the purchase location.


In Figure 1, Markets A, B, C are close, and Markets D, E, F are close by distance. Depending on the density of the market and house, dense markets form a cluster, e.g., *C*<sup>1</sup> and *C*2, and the cluster can be assumed as one commercial district. We can get the confidence and the support of beer→diaper for each cluster. →

**Figure 1.** An example of association rule mining considering purchase location.

→ → → → → The support of beer→diaper is 0.8 (4/5), and the confidence of beer→diaper is 1 (4/4) in *C*1. The support of beer→diaper is 0.2 (1/5), and the confidence of beer→diaper is 0.25 (1/4). Even if the minimum support and confidence are set to 0.5, we can find the association rule with beer→diaper [sup: 0.8, conf: 1]. For example, data analysts can infer that there is a lot of households with babies around the *C*<sup>1</sup> commercial district from these association rules. With this knowledge, it is possible to set up a strategy for promoting baby products in the market of the relevant commercial district. In this way, association rules that

were not discovered when analyzing the entire data can be discovered in data generated in a specific region. Association rules discovered in a specific region can be used as information to analyze the purchasing patterns or behavioral characteristics of consumers in that region. Until now, many association rule algorithms have been developed to discover association rules in the entire data, but no algorithm has yet been proposed to discover association rules effectively in partial transactions.

In this paper, we propose region-based FP-Growth (RFP-Growth) that discovers frequent patterns for each divided cluster after dividing the entire transaction data into density-based clusters. RFP-Growth algorithm generates FP-Tree with only transactions in those regions when the regions to find the association rule is selected. RFP-Growth discovers discover new frequent rules that were not found in the whole data. The contributions of this paper are summarized as follows.


The rest of this paper is organized as follows. Section 2 reviews related works to spatial clustering algorithms with FP-Growth and defines the problem. In Section 3, we describe an overview of RFP-Growth. In Section 4, we present experimental results and their evaluation. In Section 5, we conclude our work and present some directions for future research.

#### **2. Background and Related Works**

#### *2.1. Background: FP-Growth*

Apriori algorithm is the most representative algorithm for association rules and is a useful algorithm for finding frequent itemsets for binary association rules [9,17]. However, since candidate itemsets are repeatedly generated and the support is calculated while scanning the database, a lot of processing time is consumed. To compensate for this drawback, several studies have been conducted to reduce the number of candidate sets or the number of database scans. FP-Growth algorithm is attracting attention because it can analyze frequent patterns with only two database scans without generating a candidate set [10,18]. Important and quantitative information about frequent itemsets is stored in an extended prefix tree structure called FP-Tree. FP-Tree generates a frequency pattern tree with only two database scans. The priority of items is determined by counting the number of frequent occurrences of each item through the first database scan. Each set of items entered through the second database scan is sorted using the number of frequent occurrences.

A simple example of constructing FP-Tree is shown in Figure 2. Figure 2a is an example transaction database for creating FP-Tree (the minimum support is set to three). Each row is composed of a set of items that occur simultaneously within one transaction and is classified by transaction identification (TID). To construct FP-Tree using this example transactional database, first, we need to find the frequency of the items. The database is scanned once for the first time to count the number of items represented in the database. Then, in order to make a list of frequent items, only items with a minimum support rating or higher are used to create the FP-Tree in the order of the highest frequency. Figure 2b shows items with a frequency greater than or equal to the minimum support in the order of the highest frequency.


TID Items

100 f,a,c,d,g,i,m,p

200 a,b,c,f,l,m,o


Item Count

f 4

c 4


TID Items

100 f,c,a,m,p

200 f,c,a,b,m

**Figure 2.** An example of transaction database and ordered and truncated transactional database.

The next step is to scan the transaction database a second time to construct FP-Tree. Starting from the root, transactions are added one by one to the root subtree in a prefix tree method. After reading each transaction, the items are reordered in reverse order of frequency. Items that do not meet the minimum support are not considered. Figure 2c shows the transaction after omitting items with a support rating of less than three from Figure 2a.

Figure 3 shows that the process of construction of FP-Tree. The process consisted of the four-step to add the five transactions of Figure 2a to FP-Tree. Figure 4 shows the final FP-Tree and its header table for the transaction database. FP-Tree reduces frequent database scans compared to Apriori algorithm. Since FP-Tree does not generate candidate sets, it is useful for finding frequent itemsets from large amounts of data. However, when the depth of the tree increases and the number of nodes increases, the dependence of the memory size is large, and a lot of processing time may be consumed for mining.

(a) (b) m:1 m:1 (c) (d) **Figure 3.** A process of FP-Tree construction. (**a**) Transaction (f,c,a,m,p) is inserted, (**b**) transaction (f,c,a,b,m) is inserted, (**c**) transaction (f,b) is inserted, (**d**) transaction (c,b,p) is inserted.

c:1

c:1

b:1

p:1

b:1

p:1

b:1

b:1

m:1

p:2

p:1

b:1

b:1

m:1

m:2

p:2

(a) Header Table (b) FP-tree

(a) Header Table (b) FP-tree

root

root

f:4

c:3

a:3

m:2

p:2

f:4

p:1

Item Count f 4 c 4 a 3 m 3 p 3 b 3

Item Count f 4 c 4 a 3 m 3 p 3 b 3

Head of node links

Head of node links

p:1

m:1

(a) Header Table (b) FP-tree

**Figure 4.** FP-Tree built based on the data in Figure 2a.

#### *2.2. Variants of FP-Growth*

TID Items

100 f,a,c,d,g,i,m,p

TID Items

Item Count

f 4

c 4

a 3

m 3

p 3

b 3

(b) Item list ordered by frequency

root

f:3

c:2

a:2

m:1

b:1

b:1

root

f:4

c:3

a:3

m:2

b:1

b:1

c:1

b:1

p:1

m:1

p:2

(c) (d)

m:1

p:1

100 f,c,a,m,p

200 f,c,a,b,m

300 f,b

400 c,b,p

500 f,c,a,m,p

(c) Ordered and truncated Transactional database

200 a,b,c,f,l,m,o

300 b,f,h,j,o,w

400 b,c,k,s,p

500 a,f,c,e,l,p,m,n

(a) Transaction database

root

root

f:2

c:2

a:2

m:1

b:1

m:1

p:1

(a) (b)

f:1

c:1

a:1

m:1

p:1

Since the introduction of FP-Tree, various tree structures for frequency pattern mining such as COFI-tree [12], DRFP-tree [13,14], CanTree [15], DSTree [19], AFOPT-tree [20], CATS Tree [21], were presented. Since FP-Tree reads the entire database and constructs a tree using the number of frequent items, it is a data mining technique that applies only to a fixed database and cannot be used in a streaming database. In order to overcome the constraints of FP-Tree, DS-Tree for mining association rules in a streaming database is presented. DS-Tree does not use the number of frequent items but sorts the items according to the criteria set by the user so as to fit the characteristics of items such as alphabetical order or lexical order. After sorting, DS-tree is created by reading a batch, which is a set of transactions as much as the window size. DS-Tree is a tree construction method that can be applied not only to a fixed database but also to a data stream environment. While FP-Tree uses the number of item frequency as the item sorting criterion, DS-Tree uses a simple criterion such as alphabetical order or lexicographic order as a criterion for tree construction. Therefore, because the database scan to find the item sorting criteria can be omitted, a tree can be constructed with only one database scan, and a tree can be constructed even in a data stream environment. Since only one data scan is required, the time it takes to construct the tree can be reduced.

#### *2.3. FP-Growth Based on Spatial Data*

With the increase in spatiotemporal data, the problem of discovering spatiotemporal association rules in spatiotemporal databases has received considerable attention in the field of frequent pattern discovery. In addition, research on spatial frequent pattern analysis based on FP-Growth is being actively conducted.

Maiti et al. [22] proposed a Map-Reduce-based approach as a method of finding co-location patterns defined with R-proximity measure and conditional probability. The purpose of this approach is to find co-location patterns of all sizes from distributed data. The colocation rule is a model for inferring the existence or nonexistence of spatial features around the item by using the features of the item included in the rule. This approach consists of four algorithms, and FP-Growth algorithm is utilized as one method to find colocation by finding all frequent itemsets.

Lee et al. [23] proposed SFP-Growth algorithms to find spatial frequent patterns from social data. This study divides the entire space into cells on a 2D grid and manages cells hierarchically by dividing the side of a cell by four. The SFP-Growth algorithm extracts spatial frequent patterns of specific locations which explain the relative characteristics of the location. However, in this method, when a frequent pattern is extracted as the sum of distant lower cells included in the same upper cell, the frequent pattern becomes information describing the characteristics of the upper cell. In the upper cell, there are also lower cells that are not involved in the frequent pattern extraction at all. In this case, even cells that do not affect the frequent pattern extraction may be misinterpreted as having the frequent pattern property defined in the upper cell.

Kiran et al. [24] proposed frequent spatial pattern growth (FSP-Growth). This study defined interesting spatial patterns, including not only frequent items that occurred at close distances between two items but also items in which the maximum distance between two items was not greater than the user-specified *maxDis*.

#### *2.4. Problem Definition*

Let *I* = {*i*1, *i*2, . . . , *i*n} be a set of *n* binary attributes called items. Let *D* = {*t*1, *t*2, . . . , *t*m} be a set of transactions called the database. Let R = {*r*1, *r*2, . . . , *r*k} be a set of k density regions. Each transaction in *D* has a unique transaction ID, a region where the product was purchased, and contains a subset of the items in I. A rule is defined as an implication of the form:

r: X→Y, where X, Y⊆I and r⊆R. (1)

In order to select interesting rules from the set of all possible rules, constraints on various measures of significance and interest are used. The best-known constraints are minimum thresholds on support and confidence.

Let X, Y be itemsets and r be regions, r: X→Y an association rule, and T a set of transactions of a given database.

**Definition 1.** (**Support**) *Support is an indication of how frequently the itemset appears in the dataset. The support of X with respect to T is defined as the proportion of transactions t in the dataset which contains the itemset X.*

#### supp(X, r) = |{t∈T; X⊆t}|/|T|, where T.region = r

The support gives an idea of how frequent an itemset is in all the transactions.

**Definition 2.** (**Confidence**) *Confidence is an indication of how often the rule has been found to be true. The confidence value of a rule, X*→*Y, with respect to a set of transactions T, is the proportion of the transactions that contain X which also contains Y.*

$$\text{conf}(\mathbb{X}\rightarrow\mathbb{Y},\mathbf{r}) = \text{supp}(\mathbb{X}\cup\mathbb{Y}) / \text{supp}(\mathbb{X}) \text{, where } \text{Tr}\text{ region} = \mathbf{r} \tag{2}$$

We modified by adding the locality of the transaction to the support and confidence used in the existing association rule. For conciseness of expression, however, it is expressed in the same way as support and confidence.

**Problem definition**. Given a set of transactions, D, containing regions where the items were purchased, the problem of mining association rules is to generate all association rules that have support and confidence greater than the user-specified minimum support (called *minsup*) and minimum confidence (called *minconf*) respectively for user-specified regions.

#### **3. Methods**

#### *3.1. Overview of RFP-Growth*

The purpose of this study is to prove that, if frequent rules are discovered by classifying transactions by region, frequent rules that cannot be discovered in the entire data can be found. RFP-Growth first divides transactions into density-based regions. The position data could be the name or code of the store where the transaction occurred, or it could be the longitude or latitude where the transaction occurred. We assume that the raw data to be analyzed contains longitude(x) and latitude(y) data where the transaction occurred.

DBSCAN performs the clustering process using only the location data of the raw data. Through the DBSCAN, each transaction is assigned to a cluster. In Figure 5, the cluster column means the cluster number to which each transaction is assigned in the clustered transaction table. For each cluster, RFP-Tree is generated using the transaction assigned to the cluster.

Clustered transactions

**Figure 5.** Overview of RFP-Growth.

#### *3.2. Intersection-Based FP-Tree*

The existing FP-Tree constructs a tree based on the criterion of the frequency of occurrence. However, in this paper, a method of constructing FP-Tree using the intersection is adopted. RFP-Tree based on the intersection is not a method of organizing a tree by sorting items using a specific criterion, but by grouping items generated by intersection each time each transaction is entered. Only one item may be included in one node, or multiple items may be included in one node. There is no need to rearrange the items in the transaction, and there is no need to build a new tree even if a continuous transaction flows in. When a new subtree is created, the item set with the highest frequency including the input transaction among the item sets is made as to the parent node. Therefore, the latest item frequency is continuously applied to the node can be optimized whenever a transaction is entered.

Figures 6 and 7 show a process to construct RFP-Tree using the example of a transactional database in the aggregate expression method and tree structure. In the case of transactions 100 and 200 in Figure 6b, the intersection of two sets {f,c,a,m} was generated twice, and the {p} and {b} item sets were generated once. If this is presented as a tree, it can be expressed as shown in Figure 7b. Whenever a transaction is entered one by one, the item sets are finally grouped using the intersection set similar to Figure 7e. If there are no items intersected with an item of an existing transaction, such as Transaction 600 in Figure 6, a new node is created in a tree. These nodes are not considered in the process of


deriving the association rule. In this way, a tree can be constructed each time a transaction is added one by one without the process of scanning the entire transaction once.

**Figure 6.** Construction of intersection-based FP-Tree (blue circles indicate newly added transactions). (**a**) Transaction (f,c,a,m,p) is inserted, (**b**) transaction (f,c,a,b,m) is inserted, (**c**) transactions (f,c,m,p) and (f,c,a,m) are inserted, (**d**) transaction (f,b) is inserted, (**e**) transaction (b,c,p) is inserted.

**Figure 7.** Tree representation of RFP-Tree. (**a**) Transaction (f,c,a,m,p) is inserted, (**b**) transaction (f,c,a,b,m) is inserted, (**c**) transactions (f,c,m,p) and (f,c,a,m) are inserted, (**d**) transaction (f,b) is inserted, (**e**) transaction (b,c,p) is inserted.

A general FP-Tree construction scans the entire database, which is the preprocessing step of tree construction, calculates the number of items, and uses this to rank the items, sort the items in each transaction in the reverse order of the number of items. However, since RFP-Tree does not require the pre-processing step of such tree configuration, it reads the database transaction and proceeds to construct the tree, thus reducing the pre-processing cost. A general FP-Tree composes a tree by reading one transaction from a database and reading items in the transaction one by one, but the proposed FP-Tree reads one transaction and constructs FP-tree in units of transactions, which reduces the cost of time compared to a general FP-Tree.

In general, the study of extracting association rules from spatial data first divides the data into clusters and then applies the traditional association rule mining algorithm to each cluster to find association rules. Instead of creating a tree after the DBSCAN process is finished, a tree can be constructed at the same time as one cluster is constructed in DBSCAN.

A transaction consists of <TID, region, items >where TID means a unique identifying number and region means a market where the consumer purchased the item and items mean the list of items purchased by consumers.

Algorithm 1 shows how RFP-tree is built. Through the entire transaction scan, only transactions with a given region from the user are selected in each transaction. For each transaction, the treeConstruct function is called and an item is passed as a parameter (Lines 2–4). If the intersection of the item of the child node (*childNode*) and the items of the current transaction is an empty set, items are inserted into the child of the current node (*currentNode*) (Lines 6–7). *childNode* means child node of *currentNode*. If the intersection of the item of the child node (*childNode*) and the items of the current transaction is not an empty set, a new node is added to the FP-Tree (Lines 8–23). If items and items of child node are the same, increase the frequency of child node by 1. If the items are a subset of the items of a *childNode*, insert the result of the difference between *childNode* and items in child of *childNode.* The intersection of *childNode* and items is reinserted in *childNode*. The frequency of childnode is increased by 1 (Lines 11–14). If the items of a *childNode* are a subset of the *items*, the frequency of the *childNode* is increased by 1. The result of the difference between *items* and items of *childNode* is inserted into *restItems*. *treeConstruct* function with *restItem* and *childNode* set as parameters is executed (Lines 15–18). If it is not included in the above three cases, two child nodes are created (Lines 20–21). The difference between *childNode* and *items* is inserted into the first child node (Line 20), and the difference between *items* and *childNode* is inserted into the second child node (Line 21). The intersection of *childNode* and *items* is reinserted in *childNode and* the frequency of *childNode* is increased by 1 (Lines 20–23).

**Algorithm 1** TreeBuilder


**Complexity.** Existing FP-Tree construction algorithms require two database scans that need 2*n*, where *n* is the number of transactions. However, the RFP-Tree construction algorithm can create a tree with one database scan. Our proposed algorithms can reduce the number of transactions to *n*. Whenever a transaction is added one by one, the item comparison operation of the two transactions executes. The complexity of RFP-Tree construction algorithm is dominated by comparing two sets of elements. If the average number of items in one transaction is *m*, the number of times to compare common items in two transactions is *m*<sup>2</sup> . Thus, the complexity of RFP-Tree construction algorithm is *O*(*nm*<sup>2</sup> ).

#### **4. Results and Discussion**

#### *4.1. Experiment Setting*

#### 4.1.1. Algorithms

The purpose of this study is to verify whether new association rules are found when the association rule is extracted by dividing a transaction database by region compared to when the association rule is extracted for the entire data. We compared RFP-Growth algorithm with the original FP-Growth, dFIN [25] and negFIN [26]. The FP-Growth algorithm discovers frequent patterns from the transaction that consists solely of items, while RFP-Growth algorithm considers the transaction with spatial data. RFP-Growth algorithm consists of two steps.

(1) The transaction is divided into regions by clustering on spatial data included in a transaction. We used DBSCAN algorithm, a clustering algorithm that allows clusters to have an arbitrary shape because we considered a commercial area with dense stores as one region. (2) FP-Growth algorithm is performed for each transaction divided by region.

All the proposed algorithms were implemented in Java, and the experiments were conducted on an Intel Core i7 at 3.50 GHz with 32 GB memory. The parameters used for the experiments are summarized and default values are shown in boldface in Table 2.

**Table 2.** Parameters for the experiments.


"K" represents 1000.

#### 4.1.2. Data Sets

The real-world datasets and synthetic data sets are used for experiments. For a real dataset, we collected sets of purchase items made for an online retail company based in the UK during an eight-month period (https://www.kaggle.com/vijayuv/onlineretail (accessed on 1 December 2021)). The real dataset consists of 25,900 transactions, and there are 4070 items. Table 3 shows samples of real datasets. We removed unnecessary columns for the experiment, i.e., Quantity, Invoice Date, Unit Price, and Customer ID. Since the same transaction is divided into several rows, the rows of the same invoice number are combined into one row. We conducted an experiment assuming the same country as one cluster by using the country column as location information. For the synthetic data, spatial data are generated in the 2D space (0, 100) × (0, 100) to indicate a store's location, and item data are generated among 100 items totally. Items in the synthetic data are generated so that there are no duplicate items in one transaction which has an average of 20 items.



#### *4.2. The Discovery of New Association Rules*

In this section, we evaluate the effect with respect to the *minsup* on the discovery of new association rules. The *Support* means an indication of how frequently the itemset appears in the dataset. *minsup* is the minimum support for an itemset to be identified as frequent. The smaller the *minsup*, the more frequent rules are discovered. If the support of an itemset is low, there is not enough information about the relationships between items. We need to find support that elicits a reasonable number of frequent rules. We conduct experiments with various *minsup* [0.2, 0.7], and set *n* = 10,000 and *k* = 5. Since FP-Growth, dFIN, and negFIN algorithms yield the same rules as a result, we compared the results of the FP-Growth algorithm to see if RFP-Growth algorithm discovers new rules.

Figure 8 shows the number of newly discovered frequent rules according to the support level from the synthetic datasets. The left y-coordinate represents the number of the frequent rules found in FP-Growth. The right y-coordinate represents the number of the frequent rules that are not found in FP-Growth and are newly discovered in RFP-Growth. As *minsup* becomes larger, the number of the frequent rules discovered decreases. As *minsup* increases, the number of newly discovered rules decreases. In the section where the number of the frequent rules discovered in FP-Growth is maintained, [0.22–0.3, 0.34–0.44, 0.5–0.68], the number of newly discovered frequent rules in RFP-Growth is low. It can be seen that when the number of the frequent rules discovered in FP-Growth is reduced, the number of the frequent rules newly discovered in RFP-Growth increases. When *minsup* was 0.7, no rules were discovered in FP-Growth, but 20 rules were discovered in RFP-Growth.

**Figure 8.** The number of discovered frequent rules in FP-Growth and RFP-Growth from the synthetic data.

Figure 9 shows the number of newly discovered frequent rules according to the support level from the real datasets. The left y-coordinate represents the number of the frequent rules found in FP-Growth. The right y-coordinate represents the number of the frequent rules that are not found in FP-Growth and are newly discovered in RFP-Growth. We conduct experiments with various *minsup* [0.0001, 0.001], and set *n* = 1,044,000 and *k* = 50. In the section where the number of the frequent rules discovered in FP-Growth is maintained, [0.0001–0.0002, 0.0006–0.001], the number of newly discovered frequent rules in RFP-Growth is low. It can be also seen that when the number of the frequent rules discovered in FP-Growth is reduced, the number of the frequent rules newly discovered in RFP-Growth increases. When *minsup* was 0.0006, 0.0008 and 0.001, no rules were discovered in FP-Growth, but 206,106, 13,765 and 380 rules were discovered in RFP-Growth respectively.

**Figure 9.** The number of discovered frequent rules in FP-Growth and RFP-Growth from the realworld data.

#### *4.3. Memory Consumption*

In this section, we measure the memory consumption with respect to the *minsup* for the real-world datasets and the synthetic datasets. Figure 10 shows that the larger the *minsup*, the smaller the memory usage. This is because, in general, as *minsup* increases, the number of items treated as a frequent pattern decreases. Comparing the memory usage of RFP-Growth and FP-Growth, it was found that the memory usage decreased by 34% for synthetic datasets and 23% for real datasets. This can be explained as follows. RFP-Growth generates an FP-Tree from transaction data through an intersection operation, whereas FP-Growth generates an FP-Tree after creating an ordered and truncated transactional table in Figure 2c. dFIN and negFIN show higher memory usage than FP-Growth for low *minsup*.

**Figure 10.** Memory consumption comparison for different datasets, depending on the *minsup.* (**a**) Synthetic datasets, (**b**) real-world datasets.

The runtime comparison of RFP-Growth against FP-Growth, dFIN, and negFIN with respect to the *minsup* is shown in Figure 11. In all algorithms, it appears that the runtime cost decreases as *minsup* increases. The best performance at runtime is negFIN, which is known as the fastest algorithm, followed by dFIN, RFP-Growth, and FP-Growth. RFP-Growth shows better performance than FP-Growth, and the runtime performance of RFP-Growth is slightly lower than dFIN and negFIN. Although RFP-Growth uses less memory, it seems that the set operation to find common items increases the time cost.

**Figure 11.** Run time cost comparison for different datasets, depending on the minimum support. (**a**) Synthetic datasets, (**b**) real-world datasets.

#### *4.4. The Effect of the Number of Clusters*

In this section, we evaluate the effect with respect to the number of clusters for the realworld datasets and the synthetic datasets. We conduct experiments with the various clusters [5, 10, 15, 20, and 25]. In the synthetic datasets, we set *n* = 10,000, *minsup* = [0.32, 0.48] and *k* = 5. In the real-world datasets, we set *n* = 1,044,000, *minsup* = [0.0006, 0.0008] and *k* = 50.

Figure 12 shows the effects of the number of clusters on the number of newly discovered frequent rules in RFP-Growth. Two graphs are also shown on a linear scale. For each dataset, the number of newly discovered frequent rules in RFP-Growth is approximately proportional to the number of clusters. In both graphs, when *minsup* is high (0.48, 0.006), the number of newly discovered frequent rules gradually increases. On the other hand, when *minsup* is low (0.32, 0.008), the number of newly discovered rules increases rapidly as the number of clusters increases.

cost is different for the two *minsup* (0.32 and 0.48), but in the real dataset, there is little difference in the time cost for the two *minsup* (0.0006 and 0.0008). This difference is caused

by the difference in scale for the two datasets. What we can see from this result is that the time cost increases as the number of clusters increases.

**Figure 13.** Time cost with respect to the number of clusters in RFP-Growth algorithm. (**a**) Synthetic datasets, (**b**) realworld datasets.

#### *4.5. The Effect of the Size of Data*

To illustrate scalability, we vary the number of objects from 1K to 10K for the synthetic datasets. Other parameters are given their baseline values (Table 2). Figure 14 shows the effect of the number of objects in FP-Growth, dFIN, negFIN, and RFP-Growth. This graph is shown on a linear scale. For each algorithm, the runtime is approximately proportional to the number of objects. As shown in Figure 14, the time cost of RFP-Growth algorithm is lower than the time cost of FP-Growth. It can be seen that processing the divided data after dividing the data into several groups is faster than processing the entire data at once.

#### **5. Conclusions**

In this paper, we proposed the noble problem of discovering association rules by regions. Toward this goal, we proposed RFP-Growth, which organizes item transaction data with location data into groups and discovers association rules for each cluster. RFP-Growth divides item transaction included position data into regions by a density-based clustering algorithm. FP-Growth is performed for each transaction divided by region. The experimental results show that RFP-Growth discovers new association rules that the original FP-Growth cannot find in the whole data. RFP-Growth has a disadvantage,

however, that the performance decreases as the number of clusters increases. In future work, we plan to improve the performance of RFP-Growth, so even if the number of clusters increases, the performance is stabilized.

**Author Contributions:** Conceptualization, H.-J.J., Y.Y. and B.K.; methodology, B.K.; software, B.K.; validation, H.-J.J.; investigation, Y.Y.; data curation, B.K.; writing—original draft preparation, H.-J.J. and B.K.; writing—review and editing, J.S.P.; visualization, J.S.P.; supervision, B.K.; project administration, B.K.; funding acquisition, B.K. All authors have read and agreed to the published version of the manuscript.

**Funding:** This research was supported by industry-academic Cooperation R&D program funded by LX Spatial Informaion Research Institute(LXSIRI, Republic of Korea) [Project Name: A Study on the Establishment of Service Pipe Database for Safety Management of Underground Space/Project Number: 2021-502) and this research was funded by the Basic Science Research Program through the National Research Foundation of Korea (NRF) funded by the Korean Government (MSIT) (No. 2020R1F1A1077369) and by the Korean Government (MSIT) (No. 2021R1F1A1049387).

**Data Availability Statement:** The spatial transaction dataset is on a public dataset and available at " https://www.kaggle.com/vijayuv/onlineretail" (accessed on 1 December 2021).

**Conflicts of Interest:** The authors declare no conflict of interest.

#### **References**

