Exploration API (#233)

* draft for exploration api

* fix grammar + update images

* preview + upd description

* conflict resolution with `proof-reading` co-authored: @coszio

* conflict resolution with `proof-reading` co-authored: @coszio

* conflict resolution with `proof-reading` co-authored: @coszio

* Update qdrant-landing/content/articles/exploration-api.md

Co-authored-by: llogiq <bogusandre@gmail.com>

* Update qdrant-landing/content/articles/exploration-api.md

Co-authored-by: llogiq <bogusandre@gmail.com>

* add preview icon

---------

Co-authored-by: llogiq <bogusandre@gmail.com>
This commit is contained in:
Andrey Vasnetsov
2023-08-08 10:22:18 +02:00
committed by GitHub
co-authored by llogiq
parent bf6a31c52d
commit e72fb07457
23 changed files with 346 additions and 0 deletions
@@ -0,0 +1,200 @@
---
title: Vector Similarity beyond Search
short_description: Harnessing the full capabilities of vector embeddings
description: We explore some of the promissing new techniques that can be used to expand use-cases of unstructured data and unlock new similarities-based data exploration tools.
preview_dir: /articles_data/exploration-api/preview
small_preview_image: /articles_data/exploration-api/icon.svg
social_preview_image: /articles_data/exploration-api/preview/social_preview.jpg
weight: -1
author: Luis Cossío
author_link: https://coszio.github.io/
date: 2023-08-08T08:00:00+03:00
draft: false
keywords:
- vector similarity
- exploration
- dissimilarity
- discovery
- diversity
- recommendation
---
When making use of unstructured data, there are traditional go-to solutions that are well-known for developers:
- **Full-text search** when you need to find documents that contain a particular word or phrase.
- **Vector search** when you need to find documents that are semantically similar to a given query.
Sometimes people mix those two approaches, so it might look like the vector similarity is just an extension of full-text search. However, in this article, we will explore some promising new techniques that can be used to expand the use-case of unstructured data and demonstrate that vector similarity creates its own stack of data exploration tools.
{{< figure width=70% src=/articles_data/exploration-api/venn-diagram.png caption="Full-text search and Vector Similarity Functionality overlap" >}}
While there is an intersection in the functionality of these two approaches, there is also a vast area of functions that is unique to each of them.
For example, the exact phrase matching and counting of results are native to full-text search, while vector similarity support for this type of operation is limited.
On the other hand, vector similarity easily allows cross-modal retrieval of images by text or vice-versa, which is impossible with full-text search.
This mismatch in expectations might sometimes lead to confusion.
Attempting to use a vector similarity as a full-text search can result in a range of frustrations, from slow response times to poor search results, to limited functionality.
As an outcome, they are getting only a fraction of the benefits of vector similarity.
Below we will explore why vector similarity stack deserves new interfaces and design patterns that will unlock the full potential of this technology, which can still be used in conjunction with full-text search.
## New Ways to Interact with Similarities
Having a vector representation of unstructured data unlocks new ways of interacting with it.
For example, it can be used to measure semantic similarity between words, to cluster words or documents based on their meaning, to find related images, or even to generate new text.
However, these interactions can go beyond finding their nearest neighbors (kNN).
There are several other techniques that can be leveraged by vector representations beyond the traditional kNN search. These include dissimilarity search, diversity search, recommendations and discovery functions.
## Dissimilarity Search
The Dissimilarity —or farthest— search is the most straightforward concept after the nearest search, which can’t be reproduced in a traditional full-text search.
It aims to find the most un-similar or distant documents across the collection.
{{< figure width=80% src=/articles_data/exploration-api/dissimilarity.png caption="Dissimilarity Search" >}}
Unlike full-text match, Vector similarity can compare any pair of documents (or points) and assign a similarity score.
It doesn’t rely on keywords or other metadata.
With vector similarity, we can easily achieve a dissimilarity search by inverting the search objective from maximizing similarity to minimizing it.
The dissimilarity search can find items in areas where previously no other search could be used.
Let’s look at a few examples.
### Case: Mislabeling Detection
For example, we have a dataset of furniture in which we have classified our items into what kind of furniture they are: tables, chairs, lamps, etc.
To ensure our catalog is accurate, we can use a dissimilarity search to highlight items that are most likely mislabeled.
To do this, we only need to search for the most dissimilar items using the
embedding of the category title itself as a query.
This can be too broad, so, combining it with filters —a [Qdrant superpower](/articles/filtrable-hnsw)—, we can narrow down the search to a specific category.
{{< figure src=/articles_data/exploration-api/mislabelling.png caption="Mislabeling Detection" >}}
The output of this search can be further processed with heavier models or human supervision to detect actual mislabeling.
### Case: Outlier Detection
In some cases, we might not even have labels, but it is still possible to try to detect anomalies in our dataset.
Dissimilarity search can be used for this purpose as well.
{{< figure width=80% src=/articles_data/exploration-api/anomaly-detection.png caption="Anomaly Detection" >}}
The only thing we need is a bunch of reference points that we consider "normal".
Then we can search for the most dissimilar points to this reference set and use them as candidates for further analysis.
## Diversity Search
Even with no input provided vector, (dis-)similarity can improve an overall selection of items from the dataset.
The naive approach is to do random sampling.
However, unless our dataset has a uniform distribution, the results of such sampling might be biased toward more frequent types of items.
{{< figure width=80% src=/articles_data/exploration-api/diversity-random.png caption="Example of random sampling" >}}
The similarity information can increase the diversity of those results and make the first overview more interesting.
That is especially useful when users do not yet know what they are looking for and want to explore the dataset.
{{< figure width=80% src=/articles_data/exploration-api/diversity-force.png caption="Example of similarity-based sampling" >}}
The power of vector similarity, in the context of being able to compare any two points, allows making a diverse selection of the collection possible without any labeling efforts.
By maximizing the distance between all points in the response, we can have an algorithm that will sequentially output dissimilar results.
{{< figure src=/articles_data/exploration-api/diversity.png caption="Diversity Search" >}}
Some forms of diversity sampling are already used in the industry and are known as [Maximum Margin Relevance](https://python.langchain.com/docs/integrations/vectorstores/qdrant#maximum-marginal-relevance-search-mmr) (MMR). Techniques like this were developed to enhance similarity on a universal search API.
However, there is still room for new ideas, particularly regarding diversity retrieval.
By utilizing more advanced vector-native engines, it could be possible to take use cases to the next level and achieve even better results.
## Recommendations
Vector similarity can go above a single query vector.
It can combine multiple positive and negative examples for a more accurate retrieval.
Building a recommendation API in a vector database can take advantage of using already stored vectors as part of the queries, by specifying the point id.
Doing this, we can skip query-time neural network inference, and make the recommendation search faster.
There are multiple ways to implement recommendations with vectors.
### Vector-Features Recommendations
The first approach is to take all positive and negative examples and average them to create a single query vector.
In this technique, the more significant components of positive vectors are canceled out by the negative ones, and the resulting vector is a combination of all the features present in the positive examples, but not in the negative ones.
{{< figure width=80% src=/articles_data/exploration-api/feature-based-recommendations.png caption="Vector-Features Based Recommendations" >}}
This approach is already implemented in Qdrant, and while it works great when the vectors are assumed to have each of their dimensions represent some kind of feature of the data, sometimes distances are a better tool to judge negative and positive examples.
### Relative Distance Recommendations
Another approach is to use the distance between negative examples to the candidates to help them create exclusion areas.
In this technique, we perform searches near the positive examples while excluding the points that are closer to a negative example than to a positive one.
{{< figure width=80% src=/articles_data/exploration-api/relative-distance-recommendations.png caption="Relative Distance Recommendations" >}}
The main use-case of both approaches —of course— is to take some history of user interactions and recommend new items based on it.
## Discovery
In many exploration scenarios, the desired destination is not known in advance.
The search process in this case can consist of multiple steps, where each step would provide a little more information to guide the search in the right direction.
To get more intuition about the possible ways to implement this approach, let’s take a look at how similarity modes are trained in the first place:
The most well-known loss function used to train similarity models is a [triplet-loss](https://en.wikipedia.org/wiki/Triplet_loss).
In this loss, the model is trained by fitting the information of relative similarity of 3 objects: the Anchor, Positive, and Negative examples.
{{< figure width=80% src=/articles_data/exploration-api/triplet-loss.png caption="Triplet Loss" >}}
Using the same mechanics, we can look at the training process from the other side.
Given a trained model, the user can provide positive and negative examples, and the goal of the discovery process is then to find suitable anchors across the stored collection of vectors.
<!-- ToDo: image where we know positive and nagative -->
{{< figure width=60% src=/articles_data/exploration-api/discovery.png caption="Reversed triplet loss" >}}
Multiple positive-negative pairs can be provided to make the discovery process more accurate.
Worth mentioning, that as well as in NN training, the dataset may contain noise and some portion of contradictory information, so a discovery process should be tolerant to this kind of data imperfections.
<!-- Image with multiple pairs -->
{{< figure width=80% src=/articles_data/exploration-api/discovery-noise.png caption="Sample pairs" >}}
The important difference between this and recommendation method is that the positive-negative pairs in discovery method doesn’t assume that the final result should be close to positive, it only assumes that it should be closer than the negative one.
{{< figure width=80% src=/articles_data/exploration-api/discovery-vs-recommendations.png caption="Discovery vs Recommendation" >}}
In combination with filtering or similarity search, the additional context information provided by the discovery pairs can be used as a re-ranking factor.
## A New API Stack for Vector Databases
When you introduce vector similarity capabilities into your text search engine, you extend its functionality.
However, it doesn't work the other way around, as the vector similarity as a concept is much broader than some task-specific implementations of full-text search.
Vector Databases, which introduce built-in full-text functionality, must make several compromises:
- Choose a specific full-text search variant.
- Either sacrifice API consistency or limit vector similarity functionality to only basic kNN search.
- Introduce additional complexity to the system.
Qdrant, on the contrary, puts vector similarity in the center of it's API and architecture, such that it allows us to move towards a new stack of vector-native operations.
We believe that this is the future of vector databases, and we are excited to see what new use-cases will be unlocked by these techniques.
## Wrapping up
Vector similarity offers a range of powerful functions that go far beyond those available in traditional full-text search engines.
From dissimilarity search to diversity and recommendation, these methods can expand the cases in which vectors are useful.
Vector Databases, which are designed to store and process immense amounts of vectors, are the first candidates to implement these new techniques and allow users to exploit their data to its fullest.
@@ -3,6 +3,7 @@ title: Serverless Semantic Search
short_description: "Need to setup a server to offer semantic search? Think again!"
description: "Create a serverless semantic search engine using nothing but Qdrant and free cloud services."
social_preview_image: /articles_data/serverless/social_preview.png
small_preview_image: /articles_data/serverless/icon.svg
preview_dir: /articles_data/serverless/preview
weight: 1
author: Andre Bogus
Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.0"
width="512.000000pt"
height="512.000000pt"
viewBox="0 0 512.000000 512.000000"
preserveAspectRatio="xMidYMid meet"
id="svg18"
sodipodi:docname="earth-grid.svg"
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs22" />
<sodipodi:namedview
id="namedview20"
pagecolor="#ffffff"
bordercolor="#999999"
borderopacity="1"
inkscape:pageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="true"
inkscape:document-units="pt"
showgrid="false"
inkscape:zoom="0.42267342"
inkscape:cx="-4.7317856"
inkscape:cy="676.64535"
inkscape:window-width="2560"
inkscape:window-height="1011"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-maximized="1"
inkscape:current-layer="g16" />
<g
transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
fill="#000000"
stroke="none"
id="g16">
<path
d="M773 5109 c-297 -35 -568 -258 -658 -541 -65 -206 -49 -422 46 -611 28 -55 90 -144 314 -452 126 -172 150 -220 185 -360 37 -150 55 -182 120 -215 92 -48 215 -13 263 75 6 11 23 72 39 135 15 63 39 137 52 165 14 27 108 165 210 305 217 300 241 337 277 439 89 252 51 515 -106 736 -165 232 -454 358 -742 324z m237 -160 c80 -15 225 -89 292 -149 78 -69 151 -182 184 -283 23 -69 28 -100 28 -197 1 -201 -25 -256 -290 -620 -102 -140 -203 -290 -224 -333 -21 -43 -48 -122 -61 -175 -28 -126 -32 -134 -72 -130 l-32 3 -30 120 c-16 66 -44 150 -62 185 -17 36 -120 187 -228 335 -205 284 -244 349 -271 455 -22 86 -22 236 0 319 72 269 289 450 581 484 37 5 112 -1 185 -14z"
id="path2"
style="fill:#ffffff" />
<path
d="M724 4716 c-74 -27 -105 -49 -167 -115 -151 -161 -144 -425 15 -584 247 -246 663 -108 720 239 18 104 -20 260 -67 278 -32 12 -62 6 -83 -17 -26 -28 -27 -51 -6 -124 38 -129 -21 -259 -146 -324 -69 -36 -176 -33 -248 6 -95 52 -142 132 -142 242 0 162 113 272 278 273 64 0 76 3 97 25 14 13 25 36 25 50 0 14 -11 37 -25 50 -22 23 -32 25 -107 24 -61 0 -99 -6 -144 -23z"
id="path4"
style="fill:#ffffff" />
<path
d="M4038 5110 c-139 -25 -263 -88 -368 -187 -84 -79 -114 -127 -104 -167 8 -31 23 -44 61 -52 28 -5 38 2 119 83 64 63 108 97 155 120 184 90 392 80 559 -28 167 -107 260 -280 260 -479 0 -142 -35 -237 -139 -379 -34 -47 -61 -95 -61 -108 0 -33 42 -73 78 -73 33 0 57 23 125 121 104 148 147 278 147 443 0 119 -18 201 -64 299 -88 190 -264 339 -461 392 -71 19 -240 28 -307 15z"
id="path6"
style="fill:#ffffff" />
<path
d="M2335 4820 c-214 -16 -498 -77 -543 -115 -47 -40 -23 -125 36 -125 14 0 82 14 153 32 71 17 131 29 134 27 3 -3 -11 -45 -30 -92 -67 -167 -160 -530 -191 -749 -3 -27 -8 -48 -10 -48 -32 0 -247 -33 -267 -42 -51 -20 -61 -70 -23 -115 l24 -27 121 15 121 15 0 -26 c-1 -14 -7 -81 -14 -150 -7 -69 -10 -134 -6 -145 12 -31 37 -48 72 -47 57 1 67 23 83 183 22 207 18 197 73 206 61 10 815 10 864 0 27 -6 39 -14 43 -30 17 -74 50 -511 61 -789 l7 -178 -547 0 -546 0 7 193 c6 190 6 194 -15 215 -32 32 -85 29 -111 -4 -17 -22 -21 -41 -21 -109 0 -45 -3 -130 -7 -188 l-6 -107 -379 0 -378 0 0 50 c0 37 -5 55 -20 70 -53 53 -130 9 -130 -76 l0 -44 -262 0 -261 0 6 98 c8 119 38 289 72 405 32 110 32 130 -1 156 -33 26 -65 27 -93 4 -36 -30 -96 -267 -121 -478 -14 -115 -14 -404 0 -520 63 -523 285 -980 655 -1350 302 -302 645 -498 1050 -600 191 -48 350 -67 560 -67 241 0 422 24 641 87 123 36 334 121 361 147 31 29 30 72 -2 104 -14 14 -25 29 -25 35 0 5 -11 21 -25 34 -43 44 -68 34 -164 -60 -82 -80 -92 -86 -167 -109 -100 -30 -234 -60 -240 -54 -2 3 7 29 20 59 39 90 102 295 139 460 53 231 53 234 23 264 -32 32 -75 33 -103 2 -14 -14 -27 -53 -38 -107 -46 -238 -115 -467 -187 -621 l-40 -86 -106 -5 c-59 -3 -145 -3 -192 1 l-85 6 -37 75 c-70 140 -152 417 -198 670 -11 63 -22 122 -24 131 -3 15 26 16 338 12 187 -3 392 -1 455 5 100 8 117 12 133 32 24 29 23 69 -3 96 l-20 22 -332 -5 c-290 -4 -578 5 -593 20 -16 16 -57 499 -69 820 l-7 167 624 0 c614 0 625 0 646 20 30 29 29 82 -2 112 -23 22 -24 29 -35 293 -10 238 -23 405 -47 636 l-6 66 98 -13 c186 -26 551 -102 595 -125 9 -5 19 -19 21 -31 46 -211 69 -328 77 -398 16 -122 18 -128 51 -145 37 -19 76 -11 97 22 14 21 15 36 4 123 -7 54 -25 160 -40 235 l-28 136 25 -6 c83 -21 317 -126 449 -203 l61 -35 25 -101 c14 -56 30 -135 36 -176 7 -41 14 -90 17 -108 6 -38 39 -72 70 -72 12 0 33 9 48 21 33 26 34 71 6 225 -167 922 -876 1649 -1787 1833 -188 38 -437 55 -618 41z m301 -150 l51 0 41 -87 c74 -162 154 -435 197 -678 8 -49 18 -99 20 -110 4 -20 -1 -20 -449 -20 l-453 0 19 105 c52 292 146 608 220 743 l23 42 75 6 c41 4 104 5 140 3 36 -2 88 -4 116 -4z m324 -45 c36 -8 104 -27 153 -42 86 -26 89 -28 171 -113 187 -194 340 -439 451 -724 24 -61 42 -112 41 -114 -2 -1 -51 9 -110 23 -113 27 -331 66 -476 85 l-85 11 -23 132 c-45 255 -126 555 -188 696 -13 29 -24 55 -24 57 0 7 24 4 90 -11z m747 -327 c230 -158 448 -386 597 -628 57 -92 146 -262 146 -280 0 -6 -17 -2 -37 9 -77 39 -241 106 -348 142 l-110 36 -37 106 c-79 228 -174 424 -292 600 -36 55 -66 101 -66 104 0 6 59 -30 147 -89z m-2813 -1950 c9 -165 33 -354 66 -518 15 -74 26 -137 24 -139 -12 -14 -354 137 -471 207 l-61 37 -21 87 c-32 129 -50 241 -58 351 l-6 97 260 0 260 0 7 -122z m910 -35 c10 -243 26 -484 41 -637 20 -185 20 -184 -7 -180 -234 36 -318 50 -448 79 -243 54 -226 47 -244 108 -45 156 -89 441 -102 665 l-7 122 381 0 380 0 6 -157z m-904 -754 l135 -47 52 -143 c68 -187 183 -418 276 -558 41 -61 72 -111 70 -111 -3 0 -49 28 -102 63 -315 207 -567 489 -738 825 -29 58 -53 108 -53 113 0 4 51 -16 113 -44 61 -28 173 -72 247 -98z m422 -123 c124 -29 292 -60 447 -81 63 -8 116 -16 117 -18 0 -1 11 -58 23 -127 45 -257 111 -506 176 -668 19 -47 33 -87 30 -90 -6 -6 -147 26 -239 55 -69 22 -89 33 -144 87 -161 154 -339 420 -441 661 -39 93 -81 205 -76 205 2 0 50 -11 107 -24z"
id="path8"
style="fill:#ffffff" />
<path
d="M4041 4744 c-134 -47 -208 -147 -151 -204 31 -31 75 -26 122 15 53 45 96 58 169 53 47 -3 66 -10 96 -35 103 -82 120 -192 46 -299 -48 -71 -25 -134 48 -134 30 0 43 6 65 33 72 84 100 216 70 323 -46 162 -180 264 -346 263 -41 0 -95 -7 -119 -15z"
id="path10"
style="fill:#ffffff" />
<path
d="M3860 2701 c-367 -80 -664 -376 -748 -745 -25 -112 -22 -328 7 -441 39 -156 75 -202 138 -176 51 21 57 51 28 142 -36 114 -48 210 -42 314 14 199 84 363 217 507 106 115 204 179 352 229 80 28 111 33 223 37 109 3 144 1 220 -17 300 -72 537 -305 616 -606 43 -166 23 -385 -51 -542 -36 -77 -43 -89 -310 -458 -119 -165 -229 -320 -243 -345 -40 -68 -76 -173 -103 -295 -26 -118 -50 -155 -98 -155 -47 0 -63 28 -99 177 -22 90 -50 173 -75 225 -51 105 -434 635 -468 648 -27 11 -63 0 -84 -24 -33 -40 -19 -66 182 -343 108 -149 213 -302 233 -342 22 -44 47 -121 66 -199 36 -153 52 -194 95 -231 75 -67 182 -77 268 -27 68 40 91 84 125 236 21 93 43 160 70 215 24 47 139 217 280 410 253 347 312 446 350 585 143 524 -151 1049 -674 1206 -122 36 -345 44 -475 15z"
id="path12"
style="fill:#ffffff" />
<path
d="M3960 2249 c-63 -12 -178 -71 -233 -119 -178 -157 -223 -431 -104 -639 46 -81 136 -165 222 -206 197 -95 414 -60 576 92 106 100 159 223 159 368 0 327 -295 567 -620 504z m257 -174 c74 -32 153 -110 185 -182 18 -38 22 -67 22 -143 1 -84 -2 -102 -28 -157 -31 -68 -98 -138 -162 -171 -218 -110 -479 22 -523 264 -33 182 89 368 273 415 61 16 167 4 233 -26z"
id="path14"
style="fill:#ffffff" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.0"
width="512.000000pt"
height="512.000000pt"
viewBox="0 0 512.000000 512.000000"
preserveAspectRatio="xMidYMid meet"
id="svg20"
sodipodi:docname="servers.svg"
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs24" />
<sodipodi:namedview
id="namedview22"
pagecolor="#ffffff"
bordercolor="#999999"
borderopacity="1"
inkscape:pageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="true"
inkscape:document-units="pt"
showgrid="false"
inkscape:zoom="0.47556786"
inkscape:cx="-90.418221"
inkscape:cy="424.75536"
inkscape:window-width="2560"
inkscape:window-height="1011"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-maximized="1"
inkscape:current-layer="g18" />
<g
transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
fill="#000000"
stroke="none"
id="g18"
style="fill:#ffffff">
<path
d="M1110 5113 c-51 -8 -126 -36 -178 -65 -109 -61 -139 -103 -492 -668 -358 -574 -410 -666 -428 -756 -19 -90 -16 -574 3 -649 24 -94 71 -179 135 -247 l59 -62 -60 -63 c-68 -73 -113 -155 -134 -245 -21 -91 -21 -579 0 -663 24 -94 71 -179 135 -247 l59 -62 -60 -63 c-32 -35 -73 -91 -89 -123 -53 -105 -60 -157 -60 -455 0 -302 8 -355 63 -459 41 -78 145 -182 223 -223 119 -63 113 -63 927 -63 821 0 784 -3 813 67 19 44 11 83 -22 114 l-26 24 -757 5 -756 5 -67 33 c-76 37 -120 83 -157 162 -25 53 -26 62 -29 295 -4 255 3 330 39 399 30 59 95 121 153 148 l51 23 951 5 c825 4 953 7 970 20 35 27 43 45 44 87 0 33 -6 48 -30 72 l-31 30 -947 3 -947 3 -67 33 c-76 37 -120 83 -157 162 -25 53 -26 62 -29 295 -4 255 3 330 39 399 30 59 95 121 153 148 l51 23 2105 0 2105 0 51 -23 c58 -27 123 -89 153 -148 36 -69 43 -143 39 -394 -4 -212 -6 -241 -26 -299 -28 -77 -18 -121 32 -152 85 -52 151 1 191 156 21 83 22 571 0 663 -21 90 -66 172 -134 245 l-60 63 59 62 c32 34 73 90 89 125 55 113 61 155 61 449 0 287 -6 336 -50 434 -24 54 -611 1007 -712 1156 -44 66 -126 136 -201 172 -121 59 -43 56 -1597 55 -784 -1 -1436 -4 -1450 -6z m2940 -234 c30 -15 70 -40 88 -55 18 -16 136 -195 263 -399 l230 -370 -1036 -3 c-569 -1 -1501 -1 -2070 0 l-1036 3 230 370 c127 204 245 383 263 398 44 38 100 66 151 77 23 4 677 7 1452 7 l1410 -2 55 -26z m666 -1067 c58 -27 123 -89 153 -148 36 -69 43 -144 39 -399 l-3 -240 -33 -67 c-37 -76 -82 -120 -162 -157 l-55 -26 -2095 0 -2095 0 -55 26 c-80 37 -125 81 -162 157 l-33 67 -3 240 c-4 255 3 330 39 399 25 50 83 112 124 134 81 42 12 41 2200 39 l2090 -2 51 -23z"
id="path2"
style="fill:#ffffff" />
<path
d="M680 3616 c-71 -16 -107 -35 -157 -86 -68 -67 -88 -119 -88 -225 0 -78 4 -97 27 -140 32 -60 87 -114 148 -146 37 -20 60 -24 135 -24 106 0 158 20 225 88 51 51 75 96 88 167 41 222 -157 414 -378 366z m139 -237 c82 -81 -15 -218 -118 -165 -67 35 -78 122 -20 170 44 38 98 36 138 -5z"
id="path4"
style="fill:#ffffff" />
<path
d="M2645 3623 c-88 -23 -111 -140 -37 -190 26 -17 71 -18 912 -18 841 0 886 1 912 18 58 39 58 135 0 174 -26 17 -71 18 -897 19 -478 1 -879 0 -890 -3z"
id="path6"
style="fill:#ffffff" />
<path
d="M2618 3184 c-65 -35 -73 -121 -17 -168 l31 -26 888 0 888 0 31 26 c57 48 47 135 -19 169 -43 22 -1761 22 -1802 -1z"
id="path8"
style="fill:#ffffff" />
<path
d="M680 2336 c-71 -16 -107 -35 -157 -86 -68 -67 -88 -119 -88 -225 0 -78 4 -97 27 -140 32 -60 87 -114 148 -146 37 -20 60 -24 135 -24 106 0 158 20 225 88 51 51 75 96 88 167 41 222 -157 414 -378 366z m139 -237 c82 -81 -15 -218 -118 -165 -67 35 -78 122 -20 170 44 38 98 36 138 -5z"
id="path10"
style="fill:#ffffff" />
<path
d="M2645 2343 c-88 -23 -111 -140 -37 -190 26 -17 71 -18 912 -18 841 0 886 1 912 18 58 39 58 135 0 174 -26 17 -71 18 -897 19 -478 1 -879 0 -890 -3z"
id="path12"
style="fill:#ffffff" />
<path
d="M3405 1914 c-11 -2 -45 -9 -75 -15 -284 -54 -537 -249 -668 -514 -47 -96 -59 -130 -81 -242 l-18 -86 -54 -17 c-82 -26 -132 -54 -197 -115 -102 -94 -155 -196 -172 -329 -32 -250 123 -488 370 -572 52 -18 104 -19 1020 -19 903 0 969 1 1030 18 261 73 465 278 536 537 28 99 25 281 -4 385 -72 249 -257 437 -507 517 -35 11 -105 22 -167 25 -105 6 -107 6 -129 37 -154 211 -386 349 -643 385 -74 11 -199 13 -241 5z m283 -230 c134 -28 294 -125 390 -235 16 -19 47 -62 70 -95 23 -34 49 -65 59 -70 10 -4 77 -9 148 -9 104 -2 141 -6 187 -23 243 -89 397 -336 358 -576 -21 -135 -71 -228 -171 -321 -65 -59 -120 -91 -209 -121 -51 -17 -112 -19 -945 -22 -921 -3 -979 -1 -1054 38 -51 26 -115 92 -143 148 -19 39 -23 63 -23 137 0 78 4 97 27 140 52 98 136 156 253 175 117 19 129 33 144 175 19 185 90 335 215 461 186 185 425 254 694 198z"
id="path14"
style="fill:#ffffff" />
<path
d="M680 1056 c-71 -16 -107 -35 -157 -86 -68 -67 -88 -119 -88 -225 0 -78 4 -97 27 -140 32 -60 87 -114 148 -146 37 -20 60 -24 135 -24 106 0 158 20 225 88 51 51 75 96 88 167 41 222 -157 414 -378 366z m139 -237 c82 -81 -15 -218 -118 -165 -67 35 -78 122 -20 170 44 38 98 36 138 -5z"
id="path16"
style="fill:#ffffff" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.3 KiB