// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements.  See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License.  You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
= Affinity Colocation

In many cases it is beneficial to colocate different entries if they are often accessed together.
In this way, multi-entry queries are executed on one node (where the objects are stored).
This concept is known as _affinity colocation_.

Entries are assigned to partitions by the affinity function.
The objects that have the same affinity keys go to the same partitions.
This allows you to design your data model in such a way that related entries are stored together.
"Related" here refers to the objects that are in a parent-child relationship or objects that are often queried together.

For example, let's say you have `Person` and `Company` objects, and each person has the `companyId` field that indicates the company the person works for.
By specifying the `Person.companyId` and `Company.ID` as affinity keys, you ensure that all the persons working for the same company are stored on the same node, where the company object is stored as well.
Queries that request persons working for a specific company are processed on a single node.

////
The following image shows how data is distributed with the default affinity configuration:

*TODO*

And here is how data is distributed when you colocate persons with the companies:

*TODO image*
////

You can also colocate a computation task with the data. See link:distributed-computing/collocated-computations[Colocating Computations With Data].
////
*TODO: add examples and use cases*
////
== Configuring Affinity Key

If you do not specify the affinity key explicitly, the cache key is used as the default affinity key.
If you create your caches as SQL tables using SQL statements, the PRIMARY KEY is the default affinity key.

If you want to colocate data from two caches by a different field, you have to use a complex object as the key. That object usually contains a field that uniquely identifies the object in that cache and a field that you want to use for colocation.

There are several ways to configure a custom affinity field within the custom key, which are described below.

The following example illustrates how you can colocate the person objects with the company objects using a custom key class and the `@AffinityKeyMapped` annotation.

:javaSourceFile: {javaCodeDir}/AffinityCollocationExample.java
:dotnetSourceFile: code-snippets/dotnet/AffinityCollocation.cs
:cppSourceFile: code-snippets/cpp/src/affinity_collocation.cpp

[tabs]
--
tab:Java[]
[source,java]
----
include::{javaSourceFile}[tags=collocation;!config-with-key-configuration;!affinity-key-class,indent=0]
----
tab:C#/.NET[]
[source,csharp]
----
include::{dotnetSourceFile}[tag=affinityCollocation,indent=0]
----
tab:C++[]
[source,cpp]
----
include::{cppSourceFile}[tag=affinity-collocation,indent=0]
----

tab:SQL[]
[source,sql]
----
CREATE TABLE IF NOT EXISTS Person (
  id int,
  city_id int,
  name varchar,
  company_id varchar,
  PRIMARY KEY (id, city_id)
) WITH "template=partitioned,backups=1,affinity_key=company_id";

CREATE TABLE IF NOT EXISTS Company (
  id int,
  name varchar,
  PRIMARY KEY (id)
) WITH "template=partitioned,backups=1";
----
--

You can also configure the affinity key field in the cache configuration by using the `CacheKeyConfiguration` class.

[tabs]
--
tab:Java[]
[source,java]
----
include::{javaSourceFile}[tag=config-with-key-configuration,indent=0]
----
tab:C#/.NET[]
[source,csharp]
----
include::{dotnetSourceFile}[tag=config-with-key-configuration,indent=0]
----
tab:C++[unsupported]
--

Instead of defining a custom key class, you can use the `AffinityKey` class, which is designed specifically for the purpose of using custom affinity mapping.

[tabs]
--
tab:Java[]
[source,java]
----
include::{javaSourceFile}[tag=affinity-key-class,indent=0]
----
tab:C#/.NET[]
[source,csharp]
----
include::{dotnetSourceFile}[tag=affinity-key-class,indent=0]
----
tab:C++[unsupported]
--
