├── LICENSE ├── README.md ├── gifs ├── apache_index.gif ├── area_view.gif ├── bars_view.gif ├── dashboard.gif ├── docker.gif ├── filebeat.gif ├── first_visualization.gif ├── gauge_view.gif ├── line_view.gif ├── metric_view.gif └── pie_view.gif ├── images ├── five_shards.png ├── kibana_conditional.png ├── kibana_first.png ├── kibana_fulltext.png ├── kibana_fulltext2.png ├── kibana_second.png ├── kibana_structured.png ├── kibana_third.png ├── three_nodes.png └── two_nodes.png ├── pages ├── analytics.md ├── beats.md ├── conclusion.md ├── containers.md ├── contexts.md ├── counting.md ├── dashboard.md ├── delete.md ├── dev_vs_prod.md ├── elasticsearch.md ├── full-text.md ├── index_type_document.md ├── install.md ├── introduction.md ├── inverted_index.md ├── kibana.md ├── kibana_searches.md ├── logstash.md ├── node_cluster.md ├── rest_json.md ├── shards_replicas.md ├── shutdown.md ├── stack.md ├── structured.md ├── types_forms.md ├── updating.md └── views.md ├── scripts ├── funcs.sh ├── requests.sh └── tweets.sh └── vagrant └── Vagrantfile /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright © 2007 Free Software Foundation, Inc. 5 | 6 | Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | The GNU General Public License is a free, copyleft license for software and other kinds of works. 10 | 11 | The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. 12 | 13 | When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. 14 | 15 | To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. 16 | 17 | For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. 18 | 19 | Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. 20 | 21 | For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. 22 | 23 | Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. 24 | 25 | Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. 26 | 27 | The precise terms and conditions for copying, distribution and modification follow. 28 | 29 | TERMS AND CONDITIONS 30 | 0. Definitions. 31 | “This License” refers to version 3 of the GNU General Public License. 32 | 33 | “Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. 34 | 35 | “The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations. 36 | 37 | To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work. 38 | 39 | A “covered work” means either the unmodified Program or a work based on the Program. 40 | 41 | To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. 42 | 43 | To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. 44 | 45 | An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 46 | 47 | 1. Source Code. 48 | The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work. 49 | 50 | A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. 51 | 52 | The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. 53 | 54 | The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. 55 | 56 | The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. 57 | 58 | The Corresponding Source for a work in source code form is that same work. 59 | 60 | 2. Basic Permissions. 61 | All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. 62 | 63 | You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. 64 | 65 | Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 66 | 67 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 68 | No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. 69 | 70 | When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 71 | 72 | 4. Conveying Verbatim Copies. 73 | You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. 74 | 75 | You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 76 | 77 | 5. Conveying Modified Source Versions. 78 | You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: 79 | 80 | a) The work must carry prominent notices stating that you modified it, and giving a relevant date. 81 | b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”. 82 | c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. 83 | d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. 84 | A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 85 | 86 | 6. Conveying Non-Source Forms. 87 | You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: 88 | 89 | a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. 90 | b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. 91 | c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. 92 | d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. 93 | e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. 94 | A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. 95 | 96 | A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. 97 | 98 | “Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. 99 | 100 | If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). 101 | 102 | The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. 103 | 104 | Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 105 | 106 | 7. Additional Terms. 107 | “Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. 108 | 109 | When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. 110 | 111 | Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: 112 | 113 | a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or 114 | b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or 115 | c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or 116 | d) Limiting the use for publicity purposes of names of licensors or authors of the material; or 117 | e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or 118 | f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. 119 | All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. 120 | 121 | If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. 122 | 123 | Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 124 | 125 | 8. Termination. 126 | You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). 127 | 128 | However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. 129 | 130 | Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. 131 | 132 | Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 133 | 134 | 9. Acceptance Not Required for Having Copies. 135 | You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 136 | 137 | 10. Automatic Licensing of Downstream Recipients. 138 | Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. 139 | 140 | An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. 141 | 142 | You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 143 | 144 | 11. Patents. 145 | A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”. 146 | 147 | A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. 148 | 149 | Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. 150 | 151 | In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. 152 | 153 | If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. 154 | 155 | If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. 156 | 157 | A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. 158 | 159 | Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 160 | 161 | 12. No Surrender of Others' Freedom. 162 | If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 163 | 164 | 13. Use with the GNU Affero General Public License. 165 | Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 166 | 167 | 14. Revised Versions of this License. 168 | The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. 169 | 170 | Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. 171 | 172 | If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. 173 | 174 | Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 175 | 176 | 15. Disclaimer of Warranty. 177 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 178 | 179 | 16. Limitation of Liability. 180 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 181 | 182 | 17. Interpretation of Sections 15 and 16. 183 | If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. 184 | 185 | END OF TERMS AND CONDITIONS 186 | 187 | How to Apply These Terms to Your New Programs 188 | If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. 189 | 190 | To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found. 191 | 192 | 193 | Copyright (C) 194 | 195 | This program is free software: you can redistribute it and/or modify 196 | it under the terms of the GNU General Public License as published by 197 | the Free Software Foundation, either version 3 of the License, or 198 | (at your option) any later version. 199 | 200 | This program is distributed in the hope that it will be useful, 201 | but WITHOUT ANY WARRANTY; without even the implied warranty of 202 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 203 | GNU General Public License for more details. 204 | 205 | You should have received a copy of the GNU General Public License 206 | along with this program. If not, see . 207 | Also add information on how to contact you by electronic and paper mail. 208 | 209 | If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: 210 | 211 | Copyright (C) 212 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 213 | This is free software, and you are welcome to redistribute it 214 | under certain conditions; type `show c' for details. 215 | The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an “about box”. 216 | 217 | You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . 218 | 219 | The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . 220 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Elastic Stack para Iniciantes 2 | 3 | [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) 4 | 5 | > Autor: __[Álefe Silva](https://github.com/alefeans)__ 6 | 7 | ## Sumário 8 | 9 | 1. [Introdução](pages/introduction.md) 10 | 1. [Elasticsearch](pages/elasticsearch.md) 11 | 1. [Instalação](pages/install.md) 12 | 1. [REST e JSON](pages/rest_json.md) 13 | 1. [Index, Type e Document ?](pages/index_type_document.md) 14 | 1. [Tipos e Formas de Pesquisa](pages/types_forms.md) 15 | 1. [Full-text](pages/full-text.md) 16 | 1. [Estruturada](pages/structured.md) 17 | 1. [Analítica](pages/analytics.md) 18 | 1. [Shutdown](pages/shutdown.md) 19 | 1. [Contagem de Documentos](pages/counting.md) 20 | 1. [Entendendo melhor os contextos](pages/contexts.md) 21 | 1. [Deletando](pages/delete.md) 22 | 1. [Atualizando](pages/updating.md) 23 | 1. [Node e Cluster](pages/node_cluster.md) 24 | 1. [Shards e Replicas](pages/shards_replicas.md) 25 | 1. [Inverted Index](pages/inverted_index.md) 26 | 1. [Avançando na Stack](pages/stack.md) 27 | 1. [Kibana](pages/kibana.md) 28 | 1. [Logstash](pages/logstash.md) 29 | 1. [Pesquisas no Kibana](pages/kibana_searches.md) 30 | 1. [Criando Views](pages/views.md) 31 | 1. [Nosso primeiro Dashboard](pages/dashboard.md) 32 | 1. [Desenvolvimento vs Produção](pages/dev_vs_prod.md) 33 | 1. [Beats](pages/beats.md) 34 | 1. [Monitorando Containers](pages/containers.md) 35 | 1. [Conclusão](pages/conclusion.md) 36 | -------------------------------------------------------------------------------- /gifs/apache_index.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alefeans/elastic-stack/0ee94517d3f04bb91a6a4f1f0c134e28bb588c75/gifs/apache_index.gif -------------------------------------------------------------------------------- /gifs/area_view.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alefeans/elastic-stack/0ee94517d3f04bb91a6a4f1f0c134e28bb588c75/gifs/area_view.gif -------------------------------------------------------------------------------- /gifs/bars_view.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alefeans/elastic-stack/0ee94517d3f04bb91a6a4f1f0c134e28bb588c75/gifs/bars_view.gif -------------------------------------------------------------------------------- /gifs/dashboard.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alefeans/elastic-stack/0ee94517d3f04bb91a6a4f1f0c134e28bb588c75/gifs/dashboard.gif -------------------------------------------------------------------------------- /gifs/docker.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alefeans/elastic-stack/0ee94517d3f04bb91a6a4f1f0c134e28bb588c75/gifs/docker.gif -------------------------------------------------------------------------------- /gifs/filebeat.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alefeans/elastic-stack/0ee94517d3f04bb91a6a4f1f0c134e28bb588c75/gifs/filebeat.gif -------------------------------------------------------------------------------- /gifs/first_visualization.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alefeans/elastic-stack/0ee94517d3f04bb91a6a4f1f0c134e28bb588c75/gifs/first_visualization.gif -------------------------------------------------------------------------------- /gifs/gauge_view.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alefeans/elastic-stack/0ee94517d3f04bb91a6a4f1f0c134e28bb588c75/gifs/gauge_view.gif -------------------------------------------------------------------------------- /gifs/line_view.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alefeans/elastic-stack/0ee94517d3f04bb91a6a4f1f0c134e28bb588c75/gifs/line_view.gif -------------------------------------------------------------------------------- /gifs/metric_view.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alefeans/elastic-stack/0ee94517d3f04bb91a6a4f1f0c134e28bb588c75/gifs/metric_view.gif -------------------------------------------------------------------------------- /gifs/pie_view.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alefeans/elastic-stack/0ee94517d3f04bb91a6a4f1f0c134e28bb588c75/gifs/pie_view.gif -------------------------------------------------------------------------------- /images/five_shards.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alefeans/elastic-stack/0ee94517d3f04bb91a6a4f1f0c134e28bb588c75/images/five_shards.png -------------------------------------------------------------------------------- /images/kibana_conditional.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alefeans/elastic-stack/0ee94517d3f04bb91a6a4f1f0c134e28bb588c75/images/kibana_conditional.png -------------------------------------------------------------------------------- /images/kibana_first.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alefeans/elastic-stack/0ee94517d3f04bb91a6a4f1f0c134e28bb588c75/images/kibana_first.png -------------------------------------------------------------------------------- /images/kibana_fulltext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alefeans/elastic-stack/0ee94517d3f04bb91a6a4f1f0c134e28bb588c75/images/kibana_fulltext.png -------------------------------------------------------------------------------- /images/kibana_fulltext2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alefeans/elastic-stack/0ee94517d3f04bb91a6a4f1f0c134e28bb588c75/images/kibana_fulltext2.png -------------------------------------------------------------------------------- /images/kibana_second.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alefeans/elastic-stack/0ee94517d3f04bb91a6a4f1f0c134e28bb588c75/images/kibana_second.png -------------------------------------------------------------------------------- /images/kibana_structured.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alefeans/elastic-stack/0ee94517d3f04bb91a6a4f1f0c134e28bb588c75/images/kibana_structured.png -------------------------------------------------------------------------------- /images/kibana_third.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alefeans/elastic-stack/0ee94517d3f04bb91a6a4f1f0c134e28bb588c75/images/kibana_third.png -------------------------------------------------------------------------------- /images/three_nodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alefeans/elastic-stack/0ee94517d3f04bb91a6a4f1f0c134e28bb588c75/images/three_nodes.png -------------------------------------------------------------------------------- /images/two_nodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alefeans/elastic-stack/0ee94517d3f04bb91a6a4f1f0c134e28bb588c75/images/two_nodes.png -------------------------------------------------------------------------------- /pages/analytics.md: -------------------------------------------------------------------------------- 1 | ## Analítica 2 | 3 | Finalizando os tipos de pesquisa existentes, temos a pesquisa analítica. O Elasticsearch possui uma funcionalidade chamada _aggregations_ que permite a geração de análises sofisticadas sobre os seus dados (se parece com o GROUP BY do SQL, só que bem mais poderoso). Vamos pesquisar quais são os interesses mais populares entre nossos funcionários. Mas antes, precisamos habilitar uma estrutura chamada __fielddata__ em nosso Elasticsearch que vem desabilitada por padrão: 4 | 5 | ``` 6 | curl -XPUT http://localhost:9200/mycompany/_mapping/funcionarios -d ' 7 | { 8 | "properties": { 9 | "interesses": { 10 | "type": "text", 11 | "fielddata": true 12 | } 13 | } 14 | }' 15 | ``` 16 | 17 | Esta feature vem desabilitada por conta do consumo de memória que uma pesquisa de texto muito grande pode gerar (já que há outras formas de estruturar os seus dados à tornarem agregações mais simples de serem executadas). Como estamos apenas brincando com alguns dados fictícios, não há necessidade de se preocupar com isto agora ou se aprofundar neste assunto. Masssss, caso queira entender um pouco mais, dê uma olhada neste [link](https://www.elastic.co/guide/en/elasticsearch/reference/current/fielddata.html). 18 | 19 | Agora que habilitamos o fielddata, vamos fazer nossa pesquisa analítica: 20 | 21 | ``` 22 | curl -XGET http://localhost:9200/mycompany/funcionarios/_search?pretty -d ' 23 | { 24 | "query" : { 25 | "match_all" : {} 26 | }, 27 | "aggs" : { 28 | "maiores_interesses" : { 29 | "terms" : { 30 | "field" : "interesses" 31 | } 32 | } 33 | } 34 | }' 35 | ``` 36 | 37 | O parâmetro **"aggs"** é utilizado para descrevermos todas as nossas agregações que serão realizadas. O parâmetro **"maiores_interesses"** foi um nome fictício dado para o nosso conjunto de resultados (como um apelido), e poderia ter sido qualquer outro (ex: total_de_interesses, interesses_gerais, etc). Após nomear o nosso conjunto de resultados, usamos o parâmetro **"terms"** para descrevermos por qual(is) **"field(s)"** queremos agregar os resultados. 38 | 39 | Para facilitar a visualização, vamos observar apenas o final do resultado obtido: 40 | 41 | ``` 42 | "aggregations" : { 43 | "maiores_interesses" : { 44 | "doc_count_error_upper_bound" : 0, 45 | "sum_other_doc_count" : 0, 46 | "buckets" : [ 47 | { 48 | "key" : "esportes", 49 | "doc_count" : 2 50 | }, 51 | { 52 | "key" : "musica", 53 | "doc_count" : 2 54 | }, 55 | { 56 | "key" : "filmes", 57 | "doc_count" : 1 58 | }, 59 | { 60 | "key" : "games", 61 | "doc_count" : 1 62 | }, 63 | { 64 | "key" : "musculacao", 65 | "doc_count" : 1 66 | } 67 | ] 68 | } 69 | } 70 | } 71 | 72 | ``` 73 | 74 | Dentro de **"maiores_interesses"** temos a separação dos resultados por **"buckets"**, que nos revelam a quantidade de documentos que foram encontrados fazendo menção a cada resultado. Algo que mais "embelezado" ficaria assim: 75 | 76 | | Interesses | Documentos Encontrados 77 | | ------------- |:-------------:| 78 | | Esportes | 2| 79 | | Musica |2| 80 | | Filmes | 1| 81 | | Games | 1| 82 | | Musculação | 1| 83 | 84 | Ou seja, com uma simples pesquisa conseguimos encontrar fatores em comum sobre nossos funcionários e agora sabemos quais sãos os maiores interesses dentro de nossa empresa. Possuímos poucos dados para brincar até o momento, mas imagine em uma empresa com 5.000 funcionários. Será que conseguimos tirar algum proveito disso ? Será que conseguimos correlacionar nossos dados para encontrar benefícios que possam ser mais úteis para nossos colaboradores ? Veja possuímos poucos dados, mas já sabemos que a maioria dos nossos funcionários gostam de "música" e "esportes". 85 | 86 | Apesar de abordarmos tarefas simples com os tipos de pesquisa do Elasticsearch, a quantidade de operações, agregações e filtros possíveis são quase infinitos ! Tudo vai depender da quantidade de dados que você possui e a quantidade de regras que você quer especificar em suas buscas. 87 | 88 | Próximo: [Shutdown](/pages/shutdown.md) 89 | -------------------------------------------------------------------------------- /pages/beats.md: -------------------------------------------------------------------------------- 1 | ## Beats 2 | 3 | Ainda falando de Elastick Stack, temos mais um componente que até o momento não foi comentado durante o treinamento... o __Beats__. 4 | 5 | Existem 6 módulos do Beats para diferentes propósitos: 6 | 7 | __Filebeat:__ Faz a leitura do arquivo da log desejada, enviando-a para o Logstash que fará a inserção no Elasticsearch. 8 | 9 | __Metricbeat:__ Coleta as métricas do seu servidor (CPU, memória, IO, File system e etc) e os envia para o Elasticsearch. 10 | 11 | __Packetbeat:__ Faz a coleta de métricas de tráfego de rede e você já deve imaginar para onde ele envia. 12 | 13 | __Winlogbeat:__ Faz a coleta das logs de eventos da sua infraestrutura Windows (blé). 14 | 15 | __Auditbeat:__ Realiza um serviço de auditoria, monitorando a atividade dos usuários e processos dos seus servidores Linux (like an _auditd_). 16 | 17 | __Heartbeat:__ Verifica a disponibilidade dos seus serviços, através de pings ICPM, TCP, HTTP e etc. 18 | 19 | Neste tópico, vamos focar no Filebeat... 20 | 21 | Quando queremos monitorar servidores/aplicações externas ao nosso cluster de Elasticsearch, faz mais sentido utilizar o Filebeat do que ter o Logstash instalado em cada máquina que queremos monitorar, já que ele é muito mais leve, rápido e consome muito menos recursos computacionais. 22 | 23 | Para este exemplo, vamos subir uma máquina virtual através do __Vagrant__ para monitorarmos uma instância de Apache em outro servidor. 24 | 25 | __OBS:__ Se você já conhece um pouco mais da vida e está pensando em utilizar um container Docker de Apache, fique tranquilo que em breve iremos comentar sobre monitoração de containers. 26 | 27 | __OBS²:__ Para dar sequência à este passo você não precisa necessariamente instalar o Vagrant, embora seja _extremamente recomendado_ pela facilidade que ele te trará na criação e configuração da sua máquina virtual. Mas, se quiser criar manualmente uma máquina virtual pelo Virtual Box ou VMWare e instalar o Apache nela, fique a vontade. 28 | 29 | O Vagrant é um software que facilita a criação de máquinas virtuais através de arquivos de definição. De forma bem simples, você escreve como o seu servidor será configurado e o Vagrant faz a criação conforme está descrito no seu _Vagrantfile_. Instale o Vagrant conforme a indicação para sua distribuição no [site oficial](https://www.vagrantup.com/downloads.html). É importante que você tenha o [Virtual Box](https://www.virtualbox.org/wiki/Downloads) instalado no seu host para o Vagrant utilizá-lo como _provider_ da sua máquina virtual. Após realizar o download, faça conforme abaixo para criar o seu Vagrantfile: 30 | 31 | ``` 32 | mkdir elastic_stack/ 33 | cd elastic_stack/ 34 | vagrant init . 35 | ``` 36 | 37 | O comando `vagrant init .` fará a criação de um Vagrantfile para você editar com as configurações que você deseja para a sua máquina virtual. Mas, para facilitar ainda mais a sua vida, deixei um [Vagrantfile](/vagrant/Vagrantfile) pronto para você utilizar ! Use-o no lugar do Vagrantfile default que foi gerado e faça conforme abaixo para subir a sua _VM_ (lembrando que os comandos abaixo só irão funcionar no diretório que você utilizou o `vagrant init`): 38 | 39 | ``` 40 | vagrant up 41 | ``` 42 | 43 | Pronto, sua máquina virtual está no ar. Sim, é só isso mesmo. 44 | 45 | Na primeira vez que subimos uma VM utilizando o Vagrant, ele realiza o download da _box_ (imagem do sistema operacional que sua VM utilizará como base), o que pode ser um processo meio demorado. Nas próximas vezes que você subir sua VM, você irá notar que o start será bem mais rápido. Verifique o status da sua VM com o comando abaixo: 46 | 47 | ``` 48 | vagrant status 49 | 50 | Current machine states: 51 | 52 | default running (virtualbox) 53 | 54 | The VM is running. To stop this VM, you can run `vagrant halt` to 55 | shut it down forcefully, or you can run `vagrant suspend` to simply 56 | suspend the virtual machine. In either case, to restart it again, 57 | simply run `vagrant up`. 58 | ``` 59 | 60 | Se a saída do seu comando foi conforme o exemplo acima, quer dizer que está tudo ok com a sua VM. Agora, logue na sua VM com o comando abaixo e realize a instalação do Apache: 61 | 62 | ``` 63 | vagrant ssh 64 | [vagrant@elastic ~]$ sudo yum install httpd -y 65 | ``` 66 | 67 | Após a instalação, faça a subida do processo do Apache na sua VM: 68 | 69 | ``` 70 | [vagrant@elastic ~]$ sudo systemctl start httpd 71 | ``` 72 | 73 | Ótimo, vamos ver se esse Apache está funcionando ? 74 | 75 | No nosso Vagrantfile, correlacionamos a porta __8080__ do nosso host com a porta __80__ da nossa VM (porta padrão do Apache). Sendo assim, acesse o endereço http://localhost:8080 no seu browser e verifique se foi apresentada a mensagem "It Works !". Se sim, isso significa que a nossa correlação de portas está funcionando como deveria. Se não, provavelmente a culpa é sua. 76 | 77 | Agora vamos instalar o Filebeat para começarmos a enviar as logs da nossa nova instância de Apache para o nosso Elasticsearch: 78 | 79 | ``` 80 | [vagrant@elastic ~]$ curl -L -O https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-5.6.5-x86_64.rpm ; sudo rpm -vi filebeat-5.6.5-x86_64.rpm 81 | ``` 82 | 83 | O comando acima fará o download do pacote do Filebeat e fará a instalação do mesmo na sua VM. Vamos editar alguns campos do arquivo de configuração do Filebeat para que ele possa se conectar ao nosso Elasticsearch. Procure no arquivo /etc/filebeat/filebeat.yml os parâmetros abaixo e os edite para que contenham o seguinte conteúdo: 84 | 85 | ``` 86 | - input_type: log 87 | - /var/log/httpd/*_log 88 | 89 | output.elasticsearch: 90 | # Array of hosts to connect to. 91 | hosts: [":9200"] 92 | ``` 93 | 94 | Com os parâmetros acima, estamos informando os arquivos que o Filebeat fará a leitura. Como não faremos nenhum processamento extra em nossos arquivos de log, podemos fazer o envio direto para o Elasticsearch, sem necessariamente passar pelo Logstash. Faça a subida do processo do Filebeat com o comando abaixo: 95 | 96 | ``` 97 | [vagrant@elastic ~]$ sudo systemctl start filebeat 98 | ``` 99 | 100 | Agora, acesse o Kibana novamente e faça a criação do index gerado pelo Filebeat: 101 | 102 | ![](/gifs/filebeat.gif) 103 | 104 | Para cada servidor que desejarmos monitorar, simplesmente repetimos os passos de instalação do Filebeat e configuração do _filebeat.yml_ com os parâmetros necessários e pronto... simples não é mesmo ? 105 | 106 | Para mais informações à respeito de configuração e parametrização, acesse este __[link](https://www.elastic.co/guide/en/beats/filebeat/current/configuring-howto-filebeat.html)__ e veja as opções disponíveis que temos para configurarmos o nosso Filebeat. 107 | 108 | [Monitorando Containers](/pages/containers.md) 109 | -------------------------------------------------------------------------------- /pages/conclusion.md: -------------------------------------------------------------------------------- 1 | ## Conclusão 2 | 3 | E agora, chegamos ao final do nosso treinamento de Elastic Stack para iniciantes... mas hey, não fique triste. Afinal, se você chegou até aqui, significa que você já não é tão mais iniciante e já pode partir para algum treinamento mais _hardcore_ :) . 4 | 5 | Bem, espero ter te ajudado a entender um pouco dessa tecnologia e quem sabe, agora você possa até utilizá-la em seu ambiente de trabalho de forma mais profissional e produtiva. 6 | 7 | Sugestões, feedbacks, dúvidas ou críticas são todas bem vindas e podem me ajudar a melhorar ainda mais o conteúdo do treinamento, portanto sintam-se livres para _falar_. 8 | 9 | Compartilhe, não vai doer e pode ser que ajude alguém. 10 | -------------------------------------------------------------------------------- /pages/containers.md: -------------------------------------------------------------------------------- 1 | ## Monitorando Containers 2 | 3 | Agora vamos falar de um assunto que já está em alta há alguns anos: __containers__. Mais especificamente sobre o __[Docker](https://www.docker.com/)__, que provavelmente (dando aquela amenizada na assertividade), é a solução de containers mais famosa e utilizada produtivamente nas organizações. Por isso, decidi criar esse tópico (que pode ser visto como um _extra_), para explicar como podemos criar uma monitoração para containers de uma forma bem simples e funcional utilizando o nosso Elastic Stack. 4 | 5 | Falando de forma bem básica, o Docker é uma solução de containers que permite o isolamento da sua aplicação, junto com as suas dependências, em um ambiente de execução totalmente portável para qualquer plataforma que possua o Docker instalado. Para facilitar o entendimento, imagine o seguinte cenário: você tem uma aplicação feita em Ruby que depende de uma cacetada de bibliotecas instaladas no seu sistema operacional para poder ser executada. Seria bem chato compartilhar essa aplicação com o _mundo_ e garantir que ela vá funcionar sem nenhum problema para todos os usuários, certo ? O Docker te permite encapsular sua aplicação em forma de _container_ e este, irá conter _tudo_ que a sua aplicação precisa para ser executada. Sendo assim, quando você precisar compartilhar essa aplicação, você simplesmente compartilha a _imagem_ (que seria como o código fonte que gera o container), e qualquer pessoa que possua o Docker instalado poderá utilizar o seu software sem nenhum problema. Isso _acaba_ com alguns problemas clássicos no mundo de TI sobre aplicações sendo executadas em ambientes computacionais _"idênticos"_, mas que acabam apresentando comportamentos distintos ou até mesmo incompatibilidades. Essa é uma das principais vantagens de se utilizar o Docker, mas [existem outras](https://www.docker.com/what-container) bem interessantes também. 6 | 7 | O primeiro passo para iniciarmos a prática deste tópico, é instalar o Docker no seu host. Faça o download do pacote Community Edition do Docker para o seu sistema operacional seguindo os passos deste [link](https://www.docker.com/community-edition#/download). 8 | 9 | Após ter o Docker instalado, faça a subida do processo e verifique a versão do mesmo: 10 | 11 | ``` 12 | sudo systemctl start docker 13 | docker --version 14 | Docker version 17.12.0-ce, build c97c6d6 15 | ``` 16 | 17 | Ótimo, agora vamos subir uma instância de Logstash utilizando um outro arquivo de configuração. Crie o arquivo _logstash-docker.conf_ no diretório /config da instalação do seu Logstash (como fizemos [neste passo](/pages/logstash.md)), com o seguinte conteúdo: 18 | 19 | ``` 20 | input { 21 | gelf { 22 | type => docker 23 | port => 12201 24 | } 25 | } 26 | 27 | output { 28 | stdout {} 29 | elasticsearch { 30 | hosts => ["http:// "docker" 32 | } 33 | } 34 | ``` 35 | 36 | __OBS:__ É possível utilizar apenas __uma__ instância de Logstash com __um__ arquivo de configuração subdividido pelos tipos de entrada de dados, o que faz mais sentido do que subir diversas instâncias para cada .conf que criamos. Estamos fazendo desta forma apenas para facilitar a leitura do arquivo. 37 | 38 | A configuração acima fará com que o nosso Logstash receba as logs do nosso container através do driver __[gelf](https://docs.docker.com/config/containers/logging/gelf/)__. Estamos associando a porta __12201__, onde o Logstash receberá as entradas e as enviará para o Elasticsearch, inserindo os dados no index "docker". 39 | 40 | Faça a subida do Logstash utilizando este novo arquivo de configuração: 41 | 42 | ``` 43 | nohup ./logstash -f ../config/logstash-docker.conf & 44 | ``` 45 | 46 | Agora, vamos fazer a subida de um container de Apache utilizando o comando abaixo: 47 | 48 | ``` 49 | docker run -d -p 8080:80 --log-driver gelf --log-opt gelf-address=udp://localhost:12201 httpd 50 | ``` 51 | 52 | O comando acima realiza o download da imagem oficial do Apache, que possui o nome __"httpd"__, diretamente do [Docker Hub](https://hub.docker.com/), que é o repositório público de imagens do Docker. Após o download, o container é executado automaticamente. Vamos entender os parâmetros que passamos na subida do nosso container: 53 | 54 | __-d__ - Executa o container em background. 55 | 56 | __-p__ - Correlaciona a porta 8080 do seu host com a porta 80 do container. 57 | 58 | __--log-driver gelf__ - Informa qual será o driver de log utilizado pelo nosso container Docker. 59 | 60 | __--log-opt gelf-address__ - Com este parâmetro, informarmos o protocolo e o _servidor "gelf"_ (nesse caso, o nosso Logstash), que receberá as logs do container Docker. 61 | 62 | __httpd__ - Nome do container que será executado. 63 | 64 | Verifique a instância em execução com o comando abaixo: 65 | 66 | ``` 67 | docker ps 68 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 69 | a893835da10e httpd "httpd-foreground" 34 minutes ago Up 34 minutes 0.0.0.0:8080->80/tcp clever_dijkstra 70 | ``` 71 | 72 | Teste o seu container de Apache acessando o endereço http://localhost:8080 no seu browser. Se a mensagem "It Works" aparecer, quer dizer que está tudo ok. 73 | 74 | Agora vamos até o nosso Kibana criar o index "docker": 75 | 76 | ![](/gifs/docker.gif) 77 | 78 | Pronto, agora estamos coletando todas as logs do nosso container ! Para fazer a leitura das logs de outros containers, é só utilizar os mesmos parâmetros que utilizamos na subida do container que o resultado será o mesmo. 79 | 80 | Caso queira finalizar o seu container, utilize o comando `docker stop `: 81 | 82 | ``` 83 | docker ps 84 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 85 | 1b6ec41f9add httpd "httpd-foreground" 34 minutes ago Up 1 second 0.0.0.0:8080->80/tcp xenodochial_easley 86 | 87 | docker stop 1b6ec41f9add 88 | ``` 89 | 90 | Simples demais não é verdade ? 91 | 92 | Próximo: [Conclusão](/pages/conclusion.md) 93 | -------------------------------------------------------------------------------- /pages/contexts.md: -------------------------------------------------------------------------------- 1 | ## Entendendo melhor os contextos 2 | 3 | Até agora, aprendemos a inserir dados em nosso Elasticsearch informando o __id__ que o documento irá possuir. Um exemplo disso foi a nossa primeira inserção e o conteúdo do script [funcs.sh](/scripts/funcs.sh), onde passamos o caminho completo que o documento será inserido: 4 | 5 | ``` 6 | curl -XPUT http://localhost:9200/mycompany/funcionarios/1 7 | ``` 8 | 9 | Neste tipo de inserção, informamos o index, o type e o id (1 no exemplo acima) do documento à ser inserido. Isso nos ajuda no momento de fazer uma busca, por já sabermos o caminho completo do dado. Por ex: 10 | 11 | ``` 12 | curl -XGET http://localhost:9200/mycompany/funcionarios/1 13 | ``` 14 | 15 | A nível de teste não há problemas neste tipo de abordagem, mas não é comum informarmos o id no momento da inserção do dado por 'N' motivos. Para ids, geralmente deixamos o Elasticsearch fazer a criação dinamicamente. Ou seja, você pode inserir dados no contexto que desejar sem precisar se preocupar com um número de id. Vamos criar mais um type para o nosso index "mycompany" chamado "diretores": 16 | 17 | ``` 18 | curl -XPOST http://localhost:9200/mycompany/diretores/ -d ' 19 | { 20 | "nome": "Roberto Roberts", 21 | "idade": 40, 22 | "endereco": "Rua da Chiqueza", 23 | "hobbies": ["Jogar golf", "Fazer chiquezas"], 24 | "interesses": ["orquestras", "coisas chiques"] 25 | }' 26 | ``` 27 | 28 | Veja que utilizamos o verbo HTTP __POST__ ao invés de __PUT__. Como vimos muito anteriormente, o verbo __PUT__ fala para o Elasticsearch armazenar o dado em uma URL específica, ou seja, em um caminho completo. Já o __POST__ diz para o Elasticsearch armazenar o dado _ABAIXO_ de uma URL. Leia o diálogo abaixo para entender melhor: 29 | 30 | #### PUT VS ELASTICSEARCH 31 | 32 | ``` 33 | PUT:"Oi Elasticsearch." 34 | Elasticsearch:"Fala..." 35 | PUT:"Faz um favor ?" 36 | Elasticsearch:"Fala..." 37 | PUT:"Leva esse documento nesse endereço aqui ó... Bairro: mycompany, Rua: diretores no Numero: 1. 38 | Elasticsearch:"Beleza." 39 | ``` 40 | 41 | #### POST VS ELASTICSEARCH 42 | 43 | ``` 44 | POST:"E ai Elasticsearch, tudo bom :) ?" 45 | Elasticsearch:"Lá vem você denovo pra me dar trabalho..." 46 | POST:"Que nada ! Bom.. na verdade, eu gostaria que você enviasse um documento em um endereço pra mim." 47 | Elasticsearch:"Ta... ta... me passa o endereço." 48 | POST:"Então... fica no Bairro: mycompany, na Rua: diretores e... hmmmm." 49 | Elasticsearch:"Hmmm o que ? Qual é o número ?" 50 | POST:"Esse é o problema.. eu não tenho o número, mas precisamos entregar isso agora :(" 51 | Elasticsearch:"Ah.. que ótimo. Nesse caso, vou entregar em qualquer número que eu escolher !" 52 | ``` 53 | 54 | Tirando o _incrível mau humor_ do Elasticsearch em realizar inserções de dados, é mais ou menos isso que acontece. Se não informarmos o id, o Elasticsearch gera automaticamente um id para o nosso documento. Vamos ver qual o id que ele escolheu para o nosso _fino_ diretor: 55 | 56 | ``` 57 | curl -XGET http://localhost:9200/mycompany/diretores/_search?pretty 58 | ``` 59 | 60 | O id que ele escolheu para o meu documento foi "AWDg5HpIZFpbSN2whJNa" e provavelmente, uma outra sequência bizarra de caractes foi escolhida para você. 61 | 62 | Outro ponto que talvez você não tenha reparado, é que podemos realizar consultas a nível de ids, types ou index. Por exemplo, se eu não souber em qual type o funcionário "Claudio Silva" está inserido, eu posso realizar uma pesquisa a nível de index. Por exemplo: 63 | 64 | ``` 65 | curl -XGET http://localhost:9200/mycompany/_search?pretty -d ' 66 | { 67 | "query": { 68 | "match_phrase": { "nome": "Claudio Silva"} 69 | } 70 | }' 71 | ``` 72 | 73 | Mude o valor de "nome" para "Robert Roberts" e sua busca também encontrará o resultado. Isto acontece, pois os types "funcionarios" e "diretores" estão inseridos no mesmo index (mycompany). 74 | 75 | Próximo: [Deletando](/pages/delete.md) 76 | -------------------------------------------------------------------------------- /pages/counting.md: -------------------------------------------------------------------------------- 1 | ## Contagem de Documentos 2 | 3 | Eu odiava ver tutoriais que me ensinavam a baixar a aplicação para logo em seguida fazer a subida e executar alguma outra coisa. Chegou a hora de dar o troco ! Vamos subir novamente a nossa instância de Elasticsearch para realizar a contagem de documentos existentes em nossos índices: 4 | 5 | ``` 6 | nohup ./elasticsearch & 7 | ``` 8 | 9 | Vamos utilizar a API **_count** para contar quantos documentos existem no index "mycompany": 10 | 11 | ``` 12 | curl -XGET http://localhost:9200/mycompany/_count?pretty 13 | ``` 14 | 15 | Caso você queira contar a quantidade de documentos totais em seu Elasticsearch, é só retirar o index mycompany da pesquisa: 16 | 17 | ``` 18 | curl -XGET http://localhost:9200/_count?pretty 19 | ``` 20 | 21 | Próximo: [Entendendo melhor os contextos](/pages/contexts.md) 22 | -------------------------------------------------------------------------------- /pages/dashboard.md: -------------------------------------------------------------------------------- 1 | ## Nosso primeiro Dashboard 2 | 3 | O objetivo de um dashboard de monitoração, seja este para infraestrutura, aplicação ou negócios, é ser um _irradiador de informação_. Em um ambiente real, um dashboard deve ser composto apenas por informações __realmente__ relevantes para quem o consome. Pode parecer óbvio dizer isso, mas um dashboard com _muitas informações_ pode acabar ofuscando o que realmente precisa de atenção. 4 | 5 | No nosso exemplo, vamos preenche-lo com todas as views que [criamos anteriormente](/pages/views.md): 6 | 7 | ![](/gifs/dashboard.gif) 8 | 9 | Veja que podemos movimentar as views individualmente e também trocar as cores disponíveis. 10 | 11 | É possível compartilhar este dashboard de forma _estática_ utilizando a URL disponibilizada pela opção __"Share"__. Assim você pode compartilhar a sua criação com outros usuários (que possuam acesso ao endereço do seu Kibana, obviamente) e estes poderão visualizar os gráficos sem nenhum problema. 12 | 13 | Agora é por sua conta... pratique um pouco mais, crie outros dashboards, mude as cores e formatos disponíveis em suas views e veja o que é possível fazer com os seus dados através do Kibana. 14 | 15 | Próximo: [Desenvolvimento vs Produção](/pages/dev_vs_prod.md) 16 | -------------------------------------------------------------------------------- /pages/delete.md: -------------------------------------------------------------------------------- 1 | ## Deletando 2 | 3 | Para remover algum dado do Elasticsearch, utilizamos o verbo HTTP __DELETE__ e passamos o caminho completo do dado, conforme o exemplo abaixo: 4 | 5 | ``` 6 | curl -XDELETE http://localhost:9200/mycompany/funcionarios/1 7 | 8 | {"found":true,"_index":"mycompany","_type":"funcionarios","_id":"1","_version":2,"result":"deleted","_shards":{"total":2,"successful":1,"failed":0}} 9 | ``` 10 | 11 | Se pesquisarmos pelo funcionário de id "1", veremos que o mesmo não é mais encontrado: 12 | 13 | ``` 14 | curl -XGET http://localhost:9200/mycompany/funcionarios/1 15 | 16 | {"_index":"mycompany","_type":"funcionarios","_id":"1","found":false} 17 | ``` 18 | 19 | Tenha bastante cuidado ao apagar um dado, pois caso você esqueça de passar o "type" e o "id" do documento, podemos acabar apagando um index inteiro (types estão seguros nesta situação, pois estes são removidos utilizando um método chamado "[delete_by_query](https://www.elastic.co/guide/en/elasticsearch/reference/6.1/docs-delete-by-query.html)"). 20 | 21 | Caso queira contratar o funcionário "João Silva" execute a inserção que [fizemos anteriormente](/pages/index_type_document.md). 22 | 23 | Próximo: [Atualizando](/pages/updating.md) 24 | -------------------------------------------------------------------------------- /pages/dev_vs_prod.md: -------------------------------------------------------------------------------- 1 | ## Desenvolvimento vs Produção 2 | 3 | Até o momento, temos utilizado o Elasticsearch em modo de _desenvolvimento_. Este modo é assumido por padrão pela ferramenta, caso você não modifique o parâmetro `network.host` no arquivo principal _/config/elasticsearch.yml_. Ao configurarmos um endereço de IP para a nossa instância, o Elasticsearch passa a __exigir__ que algumas configurações adicionais sejam feitas no host em que o mesmo reside para o seu funcionamento, caso contrário será impossível até mesmo de iniciar a sua instância. 4 | 5 | Em um cenário ideal, o Elasticsearch deve ser executado sem nenhuma outra aplicação concorrente, em um servidor dedicado ao seu uso e deve ter acesso a todos os recursos computacionais disponíveis. Para isso, precisamos realizar algumas configurações no nosso sistema operacional para permitir que ele tenha mais acesso à estes recursos do que é disponibilizado por default. 6 | 7 | Pode ser que você desconheça alguns dos parâmetros de sistema operacional que iremos alterar abaixo. Tente não se prender muito a isto, para podermos forcar no que precisamos aprender sobre a nossa stack, ok :) ? 8 | 9 | Antes de mais nada, finalize todas as suas instâncias de Elasticsearch, Logstash e Kibana executando um `kill` em seus respectivos processos em execução. 10 | 11 | #### Memória Virtual e "Swapping" 12 | 13 | "Swapping" ("swappar", "fazer um swap", "dar aquela swappada", etc), faz com que a performance da sua instância caia bastante, sendo assim é recomendado que a área de swap seja desabilitado por completo com o comando `sudo swapoff -a`. Caso isso não seja possível, alterar o valor do _swapiness_ para 1 já é o suficiente. Vamos seguir com a segunda opção para o nosso ambiente. Vamos também alterar o espaço utilizado para o mapeamento de memória. Lembre-se de executar todos os comandos abaixo como __root__: 14 | 15 | ``` 16 | # sysctl -w vm.swappiness=1 17 | # sysctl -w vm.max_map_count=262144 18 | ``` 19 | 20 | #### Aumentar a quantidade de "file descriptors" 21 | 22 | O Elasticsearch pode utilizar uma grande quantidade de "file descriptors" e manter uma quantidade baixa disponível em seu sistema operacional, pode acarretar em uma real perda de dados. Edite o arquivo /etc/security/limits.conf com as seguintes diretivas para configurarmos um valor aceitável: 23 | 24 | ``` 25 | elasticsearch soft nofile 65536 26 | elasticsearch hard nofile 65536 27 | ``` 28 | 29 | Ou, execute o comando abaixo: 30 | 31 | ``` 32 | ulimit -n 65536 33 | ``` 34 | 35 | __OBS:__ "elasticsearch" é o usuário utilizado para a subida da instância. Caso esteja utilizando um usuário diferente, apenas troque e seja feliz. 36 | 37 | As configurações de memória e file descriptors podem já ser o suficiente para a subida com sucesso da sua instância de Elasticsearch em modo de produção. Vamos apresentar mais uma parametrização indicada pela [documentação](https://www.elastic.co/guide/en/elasticsearch/reference/current/system-config.html#dev-vs-prod) da Elastic, apenas para conhecimento. 38 | 39 | #### Garantir Threads suficientes 40 | 41 | Precisamos garantir que o número de threads criadas pelo Elasticsearch seja de pelo menos 4096. Configuramos isto com o comando abaixo: 42 | 43 | ``` 44 | ulimit -u 4096 45 | ``` 46 | 47 | #### Network host 48 | 49 | Agora a nossa instância está pronta para ser utilizada em o modo de produção. Edite o arquivo /config/elasticsearch.yml e altere o valor conforme abaixo: 50 | 51 | ``` 52 | network.host: 53 | ``` 54 | __OBS:__ Caso esteja querendo nomear a sua instância, altere o parâmetro `node.name:` e adicione um nome de sua preferência. 55 | 56 | Como declaramos que a nossa instância de Elasticsearch utilizará um endereço fixo no nosso host, precisamos também alterar os arquivos de configuração do Kibana e do Logstash: 57 | 58 | ``` 59 | vim kibana-5.6.5/config/kibana.yml: 60 | elasticsearch.url: "http://:9200" 61 | ``` 62 | 63 | ``` 64 | vim logstash-5.6.5/config/logstash-apache.conf 65 | hosts => [":9200"] 66 | ``` 67 | 68 | Feito isso, inicie sua instância de Elasticsearch e acompanhe a saída do arquivo _nohup.out_ para ver se nenhuma mensagem de erro será exibida. Após a subida com sucesso da sua instância, a mesma agora poderá ser acessada através do IP configurado anteriormente: 69 | 70 | ``` 71 | curl -XGET http://:9200 72 | { 73 | "name" : "EuubzCb", 74 | "cluster_name" : "elasticsearch", 75 | "cluster_uuid" : "bG-qQOdXSL-McKietkxktQ", 76 | "version" : { 77 | "number" : "5.6.5", 78 | "build_hash" : "6a37571", 79 | "build_date" : "2017-12-04T07:50:10.466Z", 80 | "build_snapshot" : false, 81 | "lucene_version" : "6.6.1" 82 | }, 83 | "tagline" : "You Know, for Search" 84 | } 85 | ``` 86 | 87 | Legal, agora temos uma instância produtiva em total funcionamento. Estes passos são essenciais para uma configuração onde o seu node de Elasticsearch precisa ser acessado por algum host remoto e é exatamente sobre isso que iremos falar agora... 88 | 89 | Próximo: [Beats](/pages/beats.md) 90 | -------------------------------------------------------------------------------- /pages/elasticsearch.md: -------------------------------------------------------------------------------- 1 | ## Elasticsearch 2 | 3 | O `Elasticsearch` é uma ferramenta de buscas _open source_ desenvolvido em Java, assim como é uma solução NoSQL de armazenamento de dados. Ou seja, ele não segue os padrões de bancos de dados SQL comuns (como o MySQL, por exemplo). 4 | 5 | Seu desenvolvimento tem como base uma biblioteca Java chamada [Apache Lucene](https://github.com/apache/lucene-solr), que é o motor de buscas open source mais avançado oferecido hoje em dia. Porém, usar todo o poder de fogo do Lucene exige um certo esforço, afinal por ser apenas uma biblioteca, você precisa trabalhar com o Java para integrá-lo com a sua aplicação (e esta tarefa pode apresentar uma certa complexidade). 6 | 7 | O Elasticsearch no entanto, se aproveita do Lucene na _indexação_ e pesquisa de documentos, retirando a sua complexidade através de uma interface super fácil de se utilizar. Além disso, vamos citar algumas características que o tornam uma ferramenta excelente e extremamente veloz: 8 | 9 | * Uma API RESTful para pesquisa, inclusão, remoção e acesso aos dados utilizando o padrão JSON. 10 | * Totalmente livre de [normalização](https://pt.wikipedia.org/wiki/Normaliza%C3%A7%C3%A3o_de_dados). 11 | * Qualquer palavra _indexada_ no Elasticsearch pode ser pesquisada da mesma forma que você faz uma busca no Google. 12 | * Altamente escalável (feito para o _Cloud Computing_). 13 | * Permite pesquisas estruturadas e analíticas em _"real time"_. 14 | * Possui uma inteligência interna que entrega o melhor resultado em relação a busca feita (análise de relevância). 15 | * Extremamente rápido. Explicaremos o por quê `:)` 16 | 17 | ## Onde usar ? 18 | 19 | Tudo bem, ficou claro o que o Elasticsearch é. Mas aonde e como eu posso utilizá-lo? 20 | 21 | __Exemplo 1:__ 22 | Bem, um dos cenários mais comuns é utilizá-lo como um agregador de logs em conjunto com o Logstash e o Kibana, que são outras ferramentas da organização _Elastic_, formando o que chamamos atualmente de `Elastic Stack` (o acrônimo `ELK` não é mais utilizado). Através desta _stack_, possuímos uma ferramenta de busca e armazenamento de documentos (Elasticsearch), uma ferramenta de agregação, filtro e envio de dados (Logstash) e por fim, uma interface gráfica web para pesquisa e análise dos dados já armazenados (Kibana). 23 | 24 | A partir disso, você sysadmin ou desenvolvedor, pode centralizar qualquer tipo de log gerado por _"qualquer coisa que gere log"_ e então, realizar análises, pesquisas de baseline ou montar dashboards de métricas pré-definidas. 25 | 26 | Vamos imaginar a seguinte situação: você é responsável por um sistema computacional que possui 30 servidores e em cada um, 30 _microserviços_ diferentes. De repente, algum problema crítico acontece com este sistema e você precisa descobrir o que ocorreu. Por instinto, você irá ler as logs do sistema para tentar entender o que houve, certo? Mas... será que você pode se dar ao luxo de logar em 30 servidores e procurar a log entre 30 microserviços diferentes em um momento de crise? 27 | 28 | Agora, se você possuir um ponto central que lhe permita realizar uma busca através de uma sintaxe super simples ou ainda que lhe permita gerar um gráfico que contabilize a quantidade de vezes que um certo erro ocorreu, será muito mais fácil de identificar o problema não concorda? Prazer, `Elastic Stack`. 29 | 30 | __Exemplo 2:__ 31 | Outra forma de se usar o Elasticsearch é como uma solução NoSQL. Como ele escala horizontalmente com extrema facilidade (escalar horizontalmente nada mais é do que adicionar novos servidores com instâncias de Elasticsearch atuando como se fosse uma, representando o que chamamos de _cluster_), é comum ver empresas utilizando-o como um _Big Data_, já que a quantidade de dados e servidores gerenciados não é um problema para o Elasticsearch (_deal with it_). Neste caso de uso em específico, o Logstash pode não existir na composição da stack, mas o Kibana pode ainda ser utilizado para visualizar os dados graficamente. 32 | 33 | Enfim, chega de conversa. Vamos ver como isso funciona na prática! 34 | 35 | Próximo: [Instalação](/pages/install.md) 36 | -------------------------------------------------------------------------------- /pages/full-text.md: -------------------------------------------------------------------------------- 1 | ## Full-Text 2 | 3 | Na pesquisa full-text você simplesmente pesquisa o que você quer sem passar nenhuma regra, agregação ou algo do tipo. Quando apresentarmos o Kibana, este tipo de pesquisa vai se apresentar de forma mais simples ainda, como uma pesquisa no Google. Vamos pesquisar as palavras "easy to use" no campo "tweet" do nosso index: 4 | 5 | ``` 6 | curl -XGET http://localhost:9200/twitter/tweet/_search?pretty -d ' 7 | { 8 | "query": { 9 | "match": { 10 | "tweet": "easy to use" 11 | } 12 | } 13 | }' 14 | ``` 15 | 16 | Se você não fez nenhuma alteração no script [tweets.sh](/scripts/tweets.sh), você deve estar visualizando 3 tweets como resposta, como estes abaixo: 17 | 18 | ``` 19 | { 20 | "took" : 8, 21 | "timed_out" : false, 22 | "_shards" : { 23 | "total" : 5, 24 | "successful" : 5, 25 | "skipped" : 0, 26 | "failed" : 0 27 | }, 28 | "hits" : { 29 | "total" : 3, 30 | "max_score" : 1.9187583, 31 | "hits" : [ 32 | { 33 | "_index" : "twitter", 34 | "_type" : "tweet", 35 | "_id" : "6", 36 | "_score" : 1.9187583, 37 | "_source" : { 38 | "date" : "2018-09-16", 39 | "name" : "Tom Michael", 40 | "tweet" : "The Elasticsearch API is really easy to use", 41 | "user_id" : 1 42 | } 43 | }, 44 | { 45 | "_index" : "twitter", 46 | "_type" : "tweet", 47 | "_id" : "11", 48 | "_score" : 0.84843254, 49 | "_sourc]e" : { 50 | "date" : "2018-09-21", 51 | "name" : "Lina Jones", 52 | "tweet" : "Elasticsearch is built for the cloud, easy to scale", 53 | "user_id" : 2 54 | } 55 | }, 56 | { 57 | "_index" : "twitter", 58 | "_type" : "tweet", 59 | "_id" : "3", 60 | "_score" : 0.17669111, 61 | "_source" : { 62 | "date" : "2018-09-13", 63 | "name" : "Lina Jones", 64 | "tweet" : "Elasticsearch means full text search has never been so easy", 65 | "user_id" : 2 66 | } 67 | } 68 | ] 69 | } 70 | } 71 | ``` 72 | 73 | Talvez você não tenha reparado, mas você acabou de fazer uma pesquisa full text. Mas calma ai... porque eu tenho três respostas para a pequisa "easy to use" se em apenas um dos tweets eu realmente tenho as palavras "easy to use" ? 74 | 75 | Bem, é ai que a graça (ou desgraça) do full text entra em ação. Repare que os três tweets retornados possuem a palavra "easy". Como a sua busca não possui nenhum filtro ou parametrização adicional, qualquer uma das três palavras "easy", "to" e "use" que compõe a sua busca, serão pesquisadas no index informado. Porém, no primeiro resultado (tweet do Tom Michael), vemos que o campo **"_score"** possui o número **"1.9187583"** como valor, correto ? Compare este número com o "\_score" dos outros resultados... 76 | 77 | O Elasticsearch verifica a relevância de um documento pela proximidade da busca realizada. Como o primeiro resultado é o que mais se aproxima da busca feita, por possuir as três palavras pesquisadas, este documento recebe um número de \_score mais alto do que os demais. É assim que o Elasticsearch mede a relevância de uma pesquisa feita com o resultado encontrado. 78 | 79 | Este é o tipo de pesquisa mais simples de se fazer e também, o mais suscetível a falhas, por acabar retornando resultados que podem não ser relevantes para a sua busca e por conta do campo **"_all"** que será explicado em breve. Agora, se quisermos pesquisar a sequência exata das palavras "easy to use", podemos utilizar o recurso "match_phrase" em nossa busca: 80 | 81 | ``` 82 | curl -XGET http://localhost:9200/twitter/tweet/_search?pretty -d ' 83 | { 84 | "query": { 85 | "match_phrase": { 86 | "tweet": "easy to use" 87 | } 88 | } 89 | }' 90 | ``` 91 | 92 | Repare que agora só obtivemos um retorno. Neste caso, a _frase_ é pesquisada como uma sequência única que deve ser respeitada. 93 | 94 | Veremos em breve que geralmente realizamos pesquisas utilizando filtros e agregações para refinarmos nossas buscas. Isto melhora os resultados encontrados e geram retornos mais rápidos, já que o Elasticsearch terá que buscar a informação em um local mais específico, ao invés de ter que varrer um index inteiro para encontrar o que foi pedido. Também veremos que ao utilizar o Kibana, podemos realizar buscas sem ao menos digitar um campo específico (como o "tweet": no exemplo acima). No primeiro caso fica fácil de entender como o Elasticsearch interpreta a busca. "Aonde tiver o valor "x" no campo "y", retorne o resultado para o usuário". Mas e no segundo caso, onde você simplesmente fala "bla" pro Elasticsearch e espera que ele te mostre aonde tem o valor "bla" ? Mais tecnicamente falando, como o Elasticsearch entende o full-text quando não passamos nenhum campo como parâmetro ? 95 | 96 | Ao indexarmos um documento, todos os valores dos campos do documento são indexados em uma única string em um campo default do Elasticsearch de nome "\_all". Por exemplo, se eu estiver indexando o documento abaixo: 97 | 98 | ``` 99 | { 100 | "nome": "Maria", 101 | "idade": 28, 102 | "endereco": "Rua Encantada", 103 | "rg": 123456789, 104 | "hobbies": ["Cantar", "Jogar xadrez"] 105 | } 106 | ``` 107 | 108 | O campo "\_all" deste documento ficaria assim: 109 | 110 | ``` 111 | { 112 | "_all": "Maria 28 Rua Encantada 123456789 Cantar Jogar xadrez 113 | } 114 | ``` 115 | 116 | Sendo assim, ao realizarmos uma pesquisa full-text sem passarmos nenhum campo como parâmetro, o Elasticsearch realiza a pesquisa em todos os campos "\_all" do index escolhido, o que é muito mais rápido do que ter que avaliar campo a campo de cada documento. Porém, pode acontecer de um campo diferente do que você quer buscar possuir um valor igual ao que você procura. Ficou estranho né ? Veja o exemplo abaixo: 117 | 118 | ``` 119 | { 120 | "nome": "Carlos", 121 | "idade": 21, 122 | "endereco": "Rua Freitas", 123 | "rg": 231496289, 124 | "hobbies": "Jogar futebol" 125 | }, 126 | { 127 | "nome": "José", 128 | "idade": 38, 129 | "endereco": "Rua Carlos", 130 | "rg": 987654321, 131 | "hobbies": "Assistir Netflix" 132 | } 133 | 134 | ``` 135 | 136 | Ao inserir estes dois documentos, o Elasticsearch geraria para cada um, as seguintes strings em seus respectivos *_all*: 137 | 138 | ``` 139 | { 140 | "_all": "Carlos 21 Rua Freitas 231496289 Jogar futebol 141 | }, 142 | { 143 | "_all": "José 38 Rua Carlos 987654321 Assistir Netflix 144 | } 145 | ``` 146 | 147 | Se eu quiser saber quantas pessoas de nome "Carlos" eu tenho no meu index e fizer uma pesquisa full-text para encontrar "Carlos", quantos retornos eu terei ? E se eu pesquisar por "Freitas", quantos retornos eu terei ? 148 | 149 | Se o meu index só possuir apenas estes dois documentos, o retorno da nossa pesquisa seria: **dois** Carlos e **um** Freitas, mesmo eu só possuindo **um** Carlos e **nenhum** Freitas. 150 | 151 | Estamos entendidos com o full-text ? 152 | 153 | Próximo: [Estruturada](/pages/structured.md) 154 | -------------------------------------------------------------------------------- /pages/index_type_document.md: -------------------------------------------------------------------------------- 1 | ## Index, Type, Document ? 2 | 3 | Agora que fizemos a instalação e garantimos que o nosso Elasticsearch está operacional, vamos entender na prática o que é um _index_, _type_ e um _document_. Para isto, vamos começar a colocar alguns dados no nosso Elasticsearch ! Execute o comando abaixo: 4 | 5 | ``` 6 | curl -XPUT -H "Content-Type: application/json" http://localhost:9200/mycompany/funcionarios/1 -d ' 7 | { 8 | "nome": "João Silva", 9 | "idade": 19, 10 | "endereco": "Avenida da Magia", 11 | "hobbies": ["Tocar guitarra", "Acampar com a familia"], 12 | "interesses": "musica" 13 | }' 14 | ``` 15 | 16 | Provavelmente você recebeu uma resposta parecida com esta: 17 | 18 | ``` 19 | {"_index":"mycompany","_type":"funcionarios","_id":"1","_version":1,"result":"created","_shards":{"total":2,"__successful__":1,"failed":0},"created":true} 20 | ``` 21 | 22 | Isto significa que o nosso documento JSON foi _indexado_ com sucesso. O _verbo_ PUT utilizado, basicamente diz para o Elasticsearch: "guarde este documento __NESTA__ url" (o POST se assemelha em funcionalidade, porém dizendo a frase: "guarde o documento __ABAIXO__ desta url". Entenderemos melhor a diferença posteriormente). 23 | 24 | Para facilitar o entedimento do conceito de _index_, _type_ e _document_, vamos fazer uma analogia com um banco de dados SQL padrão: 25 | 26 | | MySQL | Banco de Dados | Tabela | Chave Primária | Linha | Coluna 27 | | ------------- |:-------------:| -----:|-----:|-----:|-----:| 28 | | __Elasticsearch__ | __Index__ | __Type__ | __Id__ | __Document__ | __Field__ 29 | | ------------- | mycompany| funcionarios|1|Documento JSON|nome, idade...| 30 | 31 | 32 | __OBS:__ Os termos "indexar" e "index" possuem significados diferentes no universo do Elasticsearch, e também se diferenciam do conceito de _índices_ utilizados em [Banco de Dados](https://pt.wikipedia.org/wiki/%C3%8Dndice_(estruturas_de_dados)). Indexar no Elasticsearch é o mesmo que adicionar um documento JSON (como realizar um INSERT), e index é uma forma de separar logicamente dados de diferentes propósitos. 33 | 34 | Ok, temos o nosso primeiro funcionário João Silva __indexado__ no nosso __index__ mycompany ! Vamos fazer a nossa primeira consulta: 35 | 36 | ``` 37 | curl -XGET http://localhost:9200/mycompany/funcionarios/_search?pretty 38 | ``` 39 | 40 | Com o comando acima, chamamos a API padrão de buscas do Elasticsearch **_search** (o parâmetro __?pretty__ é opcional e só serve para formatar a resposta em JSON). Como não passamos nenhum parâmetro, a API sempre nos retorna os 10 primeiros resultados encontrados, que neste caso nos trouxe apenas o João (_we're hiring_). Sinta-se livre para criar e consultar mais funcionários para exercitar a sintáxe :) . 41 | 42 | Próximo: [Tipos e Formas de Pesquisa](/pages/types_forms.md) 43 | -------------------------------------------------------------------------------- /pages/install.md: -------------------------------------------------------------------------------- 1 | ## Instalação 2 | 3 | Instalar o Elasticsearch é a segunda coisa mais fácil do mundo de se fazer. A primeira é desinstalar... vamos ver como se faz? 4 | 5 | Podemos fazer o download pelo repositório da Elastic através de um gerenciador de pacotes como `dnf` ou `apt-get`, ou podemos realizar o download do .zip no site da [Elastic]( https://www.elastic.co/downloads/elasticsearch ). Para conseguir realizar todo o treinamento, não se esqueça de garantir pelo menos 4GB de memória livre no seu host, ok? 6 | 7 | Para este exemplo, vamos utilizar a segunda opção: 8 | 9 | __1°__ - Realizar o download do .zip mais atual do Elasticsearch. 10 | 11 | __2°__ - Realizar o unzip do pacote baixado em algum diretório do seu servidor. 12 | 13 | __3°__ - Pronto, Elasticsearch instalado. Fácil né? Agora vamos ver se tudo ocorreu bem? 14 | 15 | __OBS:__ Acredito que não teremos problemas de compatibilidade na maioria das operações que iremos realizar, mas para este guia estamos utilizando especificamente a versão __5.6.5__ de todas as ferramentas da stack. Caso esteja utilizando uma versão superior a 6.0 do Elasticsearch, se faz necessário adicionar um _header_ nas requisições. É só acrescentar o parâmetro _-H 'Content-Type: application/json'_ no ínicio de cada requisição que está resolvido. 16 | 17 | __OBS²:__ Como pré-requisito para utilizarmos o Elasticsearch, precisamos ter o Java 1.8 instalado em nosso host. Confira como realizar a instalação do pacote para o seu sistema operacional através deste __[ link](https://docs.oracle.com/javase/8/docs/technotes/guides/install/install_overview.html)__. 18 | 19 | 20 | Dentro do diretório gerado após a descompactação, vamos executar: 21 | 22 | ``` 23 | nohup bin/elasticsearch & 24 | ``` 25 | 26 | Dessa forma, o processo do Elasticsearch se iniciará em background. Após alguns segundos (ou se você acompanhou o start pelo nohup.out), execute o seguinte comando: 27 | 28 | ``` 29 | curl -XGET http://localhost:9200/ 30 | ``` 31 | 32 | Se você recebeu um retorno parecido com esse, quer dizer que tudo está funcionando como deveria: 33 | 34 | ``` 35 | { 36 | "name" : "XJWzjDi", # Nome da sua instância de Elasticsearch (personalizável). 37 | "cluster_name" : "elasticsearch", # Nome do cluster que a nossa instância pertence (personalizável). 38 | "cluster_uuid" : "ZH9GequzQX-oobJVGPlbjg", # Identificador universal do seu cluster (como um CPF do seu cluster). 39 | "version" : { # Dentro desta "tag" temos todas as informações sobre versão de produto. 40 | "number" : "5.6.5", # Versão do Elasticsearch. 41 | "build_hash" : "57e20f3", # "ID" da geração deste pacote de Elasticsearch. 42 | "build_date" : "2017-09-23T13:16:45.703Z", # Data de geração deste pacote. 43 | "build_snapshot" : false, # Irrelevante (é irrelevante sim, para de reclamar). 44 | "lucene_version" : "6.6.1" # Versão do Lucene utilizada. 45 | }, 46 | "tagline" : "You Know, for Search" # Uma resposta amigável do Elasticsearch. 47 | } 48 | ``` 49 | 50 | Próximo: [REST e JSON](/pages/rest_json.md) 51 | -------------------------------------------------------------------------------- /pages/introduction.md: -------------------------------------------------------------------------------- 1 | # Elastic Stack para iniciantes 2 | 3 | Quando comecei a estudar sobre `Elastic Stack`, encontrei diversos livros e artigos que ofereciam ótimos conteúdos, porém que apresentavam explicações um pouco "pesadas" para quem estava iniciando no assunto. Em alguns momentos, me vi gastando muito tempo em pesquisas intermediárias sobre os conceitos, sub-tópicos ou ferramentas adjacentes à stack, para tentar entender sobre o que o assunto principal tratava. 4 | 5 | Não que isso seja algo completamente ruim, afinal cada tecnologia é um universo composto por outros "_universos menores_" e geralmente, estudar artigos técnicos tende a ser desta forma. Porém, penso que muitas vezes isso pode acabar dificultando o aprendizado de alguém que está querendo aprender uma tecnologia nova. 6 | 7 | Tendo esse pensamento em mente, decidi criar este repositório para explicar um pouco do que aprendi sobre a _stack_, utilizando uma linguagem mais informal e amigável, mas sem deixar de apresentar os conceitos essenciais. Como pré-requisito para o bom andamento deste treinamento, um conhecimento _razoável_ em Linux é o suficiente. 8 | 9 | Aviso desde já, que o objetivo deste repositório não é ser um guia de referência ou apresentar um conteúdo nível _expert_, mas sim te tornar apto a utilizar as ferramentas no seu dia-a-dia, compreendendo o funcionamento básico de cada componente que compõe a stack. 10 | 11 | Sendo assim, todos os passos descritos neste repositório tendem a demonstrar a forma mais rápida de se chegar ao objetivo proposto, sem perder tempo com configurações paralelas. 12 | 13 | Não se preocupe se em alguns momentos aparecerem termos confusos que ainda não foram explicados, pois ao longo do treinamento eles se tornarão claros para você :) 14 | 15 | Próximo: [Elasticsearch](/pages/elasticsearch.md) 16 | -------------------------------------------------------------------------------- /pages/inverted_index.md: -------------------------------------------------------------------------------- 1 | ## Inverted Index 2 | 3 | Nosso último ponto antes de partirmos para as outras ferramentas da stack será totalmente teórico e irá abordar sobre _uma das_ funcionalidades que tornam o Elasticsearch extremamente rápido na hora de fazer suas pesquisas, o __inveterd index__. 4 | 5 | O inverted index ou índice invertido (_high level fluent traduction_), é uma estrutura que consiste em uma lista de todas as únicas palavras que aparecem em qualquer documento, e para cada palavra, uma lista de documentos em que ela aparece. Para facilitar o entendimento, vamos supor que possuímos dois documentos, cada um com um campo chamado __"informacao"__, contendo os seguintes valores: 6 | 7 | __1°__ - O bulldog frances gosta de pular na grama 8 | 9 | __2°__ - Bulldog frances saltou na grama com gosto 10 | 11 | Um índice invertido destes documentos seria criado da seguinte forma: Primeiro, o conteúdo do campo _informacao_ é dividido em palavras separadas (o que o Elasticsearch denomina de __"terms"__ ou __"tokens"__). Depois, criamos uma lista de todos os "termos" únicos e então, listamos em quais documentos cada termo aparece. O resultado seria como a tabela abaixo: 12 | 13 | | Termo | Documento_1 | Documento_2 | 14 | | ------- |-----------|-------------| 15 | |Bulldog | | __X__ | 16 | |O | __X__ | | 17 | |bulldog | __X__ | | 18 | |de | __X__ | | 19 | |frances | __X__ | __X__ | 20 | |na | __X__ | __X__ | 21 | |pular | __X__ | | 22 | |saltou | | __X__ | 23 | |gosto | | __X__ | 24 | |grama | __X__ | __X__ | 25 | |gosta | __X__ | | 26 | |com | | __X__ | 27 | 28 | Se quisermos fazer uma pesquisa para encontrar "bulldog frances", precisamos apenas encontrar os documentos que cada termo aparece: 29 | 30 | | Termo | Documento_1 | Documento_2 | 31 | | ------- |-----------|-------------| 32 | |bulldog | __X__ | | 33 | |frances | __X__ | __X__ | 34 | |TOTAL   |     __2__ |    __1__   | 35 | 36 | Os dois documentos coincidem com a pesquisa, porém o primeiro documento possui mais proximidade com a busca, ou seja, ele é mais __relevante__ para a nossa pesquisa. Porém, existem alguns problemas com o nosso índice invertido: 37 | 38 | __1°__ - "Bulldog" e "bulldog" aparecem como termos separados, enquanto para nós usuários, eles deveriam aparecer como a mesma palavra. 39 | 40 | __2°__ - "pular" e "saltou", por mais que não sejam a mesma palavra, são sinônimos, ou seja, possuem o significado similar, independente do tempo verbal. 41 | 42 | Seja por qualquer motivo, nosso usuário pode esperar que os dois documentos sejam encontrados como resultado da busca. Portanto, se _normalizarmos_ os termos em um formato padronizado, podemos apresentar documentos que contenham termos que não são _exatamente o mesmo_ que o usuário requisitou, mas que são similares o suficiente para manter a relevância. Por exemplo: 43 | 44 | __1°__ - "Bulldog" e "O" podem ser colocados em minúsculo. 45 | 46 | __2°__ - "pular" e "saltou", podem ser indexados como apenas "pular". 47 | 48 | Agora o nosso índice ficou assim: 49 | 50 | | Termo | Documento_1 | Documento_2 | 51 | | ------- |-----------|-------------| 52 | |o | __X__ | | 53 | |bulldog | __X__ | __X__ | 54 | |de | __X__ | | 55 | |frances | __X__ | __X__ | 56 | |na | __X__ | __X__ | 57 | |pular | __X__ | __X__ | 58 | |gosto | | __X__ | 59 | |grama | __X__ | __X__ | 60 | |gosta | __X__ | | 61 | |com | | __X__ | 62 | 63 | Agora nossos documentos estão mais """"_encontráveis_"""", certo ? Esse processo de normalização é chamado de __"analysis"__ pelo Elasticsearch e é utilizado para facilitar a busca de documentos que possam indicar o mesmo significado, mesmo se o conteúdo não for exatamente o requisitado. 64 | 65 | O Elasticsearch fornece diversos "analisadores" que você pode utilizar na hora de padronizar seus documentos. Como este tópico é apenas explicativo, não iremos realizar nenhuma alteração em nossos dados. De qualquer forma, saiba que este é um ponto muito importante e que deve ser avaliado com atenção em um ambiente real. Para mais informações, segue o bom e velho link da documentação da [Elastic](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-analyzers.html). 66 | 67 | Próximo: [Avançando na Stack](/pages/stack.md) 68 | -------------------------------------------------------------------------------- /pages/kibana.md: -------------------------------------------------------------------------------- 1 | ## Kibana 2 | 3 | Se tudo deu certo, você deve estar visualizando a tela inicial do Kibana com algumas informações sobre o seu cluster de Elasticsearch. Atualize esta página e provavelmente você será direcionado para a seção "Management" do Kibana. Nesta seção, escolhemos quais índices iremos buscar em nosso Elasticsearch para a visualizarmos no Kibana. Mude no campo "index pattern" o valor "logstash-\*" para "mycompany". Após isto, crie em "create": 4 | 5 | ![](/images/kibana_first.png) 6 | 7 | Você será direcionado para uma página onde todos os campos do seu index poderão ser visualizados. Nesta página é possível alterar algumas coisinhas em seus campos, como tipo de dado e etc. Não vamos mexer em nada nesta tela, ok ? Ao invés disso, vamos entender as opções apresentadas no menu lateral esquerdo: 8 | 9 | __Discover -__ Nesta aba podemos ver graficamente os dados armazenados no Elasticsearch. Podemos utilizar filtros e pesquisar nossos dados através da [Lucene Syntax](https://lucene.apache.org/core/2_9_4/queryparsersyntax.html), que é uma sintáxe de pesquisa super simples (vocês vão ver). 10 | 11 | __Visualize -__ Permite a criação de visualizações customizadas utilizando diversos modelos prontos para edição. 12 | 13 | __Dashboard -__ Nesta página, conseguimos agregar as views criadas na aba “Visualize” em um só dashboard. 14 | 15 | __Timelion -__ Permite gerar gráficos de diferentes índices em diferentes períodos de tempo através de expressões regulares. Inicialmente pode parecer um pouco complexo, mas esta feature oferece um grande poder de busca e comparação. 16 | 17 | __Dev Tools -__ Possibilita realizar as pesquisas através de chamadas REST, como fizemos pela linha de comando. 18 | 19 | __Management-__ Gerenciamento dos índices e configurações avançadas do Kibana. 20 | 21 | Vamos acessar a aba "Discover" . E olha ! Todos os dados do nosso index "mycompany" estão aqui: 22 | 23 | ![](/images/kibana_second.png) 24 | 25 | Na imagem acima, perceba que fiz a expansão do documento da "Maria Costa", visualizando uma tabela com todos os campos e valores deste documento. Embaixo do nome do nosso index, podemos ver os campos disponíveis para realizarmos alguns filtros visuais. Veja na imagem abaixo que utilizei o filtro de "nome" e "interesses" para facilitar a visualização dos dados: 26 | 27 | ![](/images/kibana_third.png) 28 | 29 | Temos pouquíssimos dados para criar um dashboard bonito e apresentá-lo ao chefe ou para fazermos um belo quadro (que é o objetivo real desse treinamento). Mas enquanto estamos nesta situação, vamos criar uma visualização simples para apurarmos nossas habilidades estatísticas para o nosso __dashboard final__. Siga as instruções abaixo para a criação da nossa primeira _view_: 30 | 31 | ![](/gifs/first_visualization.gif) 32 | 33 | Mexer no Kibana é muito simples e o gif é auto-explicativo... mas vamos mastigar um pouco mais o que foi feito. Escolhemos a opção default "Count" na primeira _"Aggregation"_, que fará a contagem de vezes que um item é encontrado. Em nossos "buckets", fizemos a agregação (_high translation capability_), pelo termo "interesses". As "custom labels" são opcionais e só servem para facilitar a leitura dos campos nos gráficos. No final, criamos um gráfico em formato de pizza, com as fatias separadas pelos interesses dos nossos funcionários, de acordo com a porcentagem de valores encontrados. Se parece com a busca __analítica__ que [fizemos anteriormente](/pages/analytics.md) no Elasticsearch não é verdade ? Pois é exatamente a mesma operação. Viu como é muito mais simples quando utilizamos o Kibana ? 34 | 35 | Para explorarmos o _Lucene Query Syntax_ e gerarmos gráficos mais interessantes, precisamos de uma massa de dados maior do que a que possuímos. Sendo assim, vamos gerar esta massa ! 36 | 37 | [Logstash](/pages/logstash.md) 38 | -------------------------------------------------------------------------------- /pages/kibana_searches.md: -------------------------------------------------------------------------------- 1 | ## Pesquisas no Kibana 2 | 3 | Vamos executar algumas pesquisas para entendermos a Lucene Syntax e vermos como os tipos de pesquisas se comportam no Kibana. 4 | 5 | ### Full-Text 6 | 7 | Lembra que eu havia dito que pesquisas full-text no Kibana se parecem com pequisas feitas no Google ? Faça o seguinte, vá até a aba "Discover" e utilize a barra de search para procurar pelo nome do seu host: 8 | 9 | ![](/images/kibana_fulltext.png) 10 | 11 | Não está convencido ? Procure por "gif", "access_log" ou "curl": 12 | 13 | ![](/images/kibana_fulltext2.png) 14 | 15 | Vejam que não passamos nenhum campo como parâmetro de busca e mesmo assim ele foi capaz de encontrar os documentos. 16 | 17 | ### Estruturada 18 | 19 | Caso o nosso objetivo seja encontrar um valor em um campo específico, é só fazer da seguinte forma: 20 | 21 | ![](/images/kibana_structured.png) 22 | 23 | Na pesquisa acima, estamos buscando o retorno "200" no campo "message", que é o código de requisição atendida com sucesso pelo Apache 24 | 25 | E se quisermos adicionar uma condição em nossa pesquisa ? É só utilizarmos os [operadores condicionais](https://lucene.apache.org/core/2_9_4/queryparsersyntax.html) da Lucene Syntax. Na pesquisa abaixo, vamos pesquisar todas as respostas "200" em todos os hosts com o nome "fedora-host": 26 | 27 | ![](/images/kibana_conditional.png) 28 | 29 | ### Analítica 30 | 31 | Resultados analíticos são melhor observados utilizando as views do Kibana e a nossa [primeira view](/pages/kibana.md) foi um ótimo exemplo disto. Sendo assim, vamos partir para a criação de nossos dashboards ! 32 | 33 | 34 | Próximo: [Criando Views](/pages/views.md) 35 | -------------------------------------------------------------------------------- /pages/logstash.md: -------------------------------------------------------------------------------- 1 | ## Logstash 2 | 3 | O Logstash tem a função básica de receber dados de diferentes fontes, fazer a transformação desses dados (ou não) e então, realizar a inserção no Elasticsearch. As fontes de dados podem ser inputs manuais, logs de sistema operacional (como o "/var/log/messages"), logs de aplicação ou qualquer "outra coisa" que possa ser lida. 4 | 5 | Como fonte de dados, vamos utilizar o Web Server mais famoso do mundo, o _Apache HTTP server_. Faça a instalação do Apache utilizando o gerenciador de pacotes da sua distribuição Linux: 6 | 7 | ``` 8 | sudo dnf install httpd 9 | ``` 10 | 11 | Após realizar a instalação, faça a subida do processo: 12 | 13 | ``` 14 | systemctl start httpd 15 | ``` 16 | 17 | __OBS:__ Em algumas distribuições o Apache já vem instalado por default, em outras o nome do pacote pode ser diferente. Isto pode alterar a forma de instalação e de subida do processo. Na dúvida, dê uma pesquisada rápida no Google que você encontrará a resposta :) 18 | 19 | Para testar se está tudo ok com o seu Apache, acesse o endereço "http://localhost:80" no seu browser. Se aparecer a página do Apache, significa que tudo deu certo com a sua instalação. 20 | 21 | Em distribuições baseadas em Red Hat, as logs do Apache são armazenadas no diretório "/var/log/httpd". Sendo assim, vamos criar o arquivo de configuração do Logstash para ler as logs deste diretório. Caso você esteja utilizando uma distribuiçao diferente, as logs podem estar em outro caminho (possivelmente em "/var/log/apache2", mas dá uma olhada ai que você acha fácil) . No diretório de instalação do Logstash, vá até o caminho "/config", crie o arquivo _"logstash-apache.conf"_ e cole o conteúdo abaixo: 22 | 23 | ``` 24 | input { 25 | file { 26 | path => "/var/log/httpd/*_log" 27 | start_position => "beginning" 28 | } 29 | } 30 | 31 | output { 32 | elasticsearch { 33 | hosts => ["localhost:9200"] 34 | index => "apache" 35 | } 36 | stdout {} 37 | } 38 | ``` 39 | 40 | Os arquivos de configuração do Logstash possuem 3 seções: 41 | 42 | __input:__ Aqui, configuramos todas as entradas dos dados. Estamos utilizando o plugin __"file"__, que é utilizado para a leitura de arquivos (_really ?_). Existem diversos plugins configuráveis como "http", "github", "jdbc" e etc (caso queira ver a listagem completa acesse este [link](https://www.elastic.co/guide/en/logstash/current/input-plugins.html)). Dentro da configuração do plugin "file", estamos informando o diretório onde o Logstash fará a leitura dos arquivos (a expressão "\*\_log" significa que todos os arquivos que terminem com "\_log" serão lidos), e também em que posição ele iniciará leitura dos arquivos. Como estamos utilizando a opção "beginning", o Logstash fará a captura de todo o conteúdo do arquivo desde a primeira linha. Caso utilizassemos a opção "end", o Logstash iniciaria a leitura do arquivo após a última entrada feita, ou seja, só as novas informações incrementadas no arquivo seriam lidas, ignorando o conteúdo anterior. De qualquer forma, estas duas opções só modificariam o comportamento inicial do Logstash com os arquivos. 43 | 44 | __filter:__ Não estamos utilizando esta opção no nosso arquivo de configuração, mas nesta diretiva podemos configurar [diversos filtros](https://www.elastic.co/guide/en/logstash/current/filter-plugins.html) para realizar a transformação dos dados antes de serem indexados no Elasticsearch. 45 | 46 | __output:__ Nesta opção, configuramos o destino dos nossos dados. Estamos utilizando o [plugin de saída](https://www.elastic.co/guide/en/logstash/current/output-plugins.html) para o endereço do nosso Elasticsearch, informando o index "apache" que será utilizado para o armazenamento das nossas logs. Também estamos utilizando o plugin "stdout" para direcionarmos a saída do processo do Logstash quando o executamos. Ao subirmos o processo, iremos direcionar esta saída para o arquivo "nohup.out". É apenas uma forma de mapear o que nosso processo está _fazendo_ em forma de log. 47 | 48 | __Atenção !__ Vai rolar uma gambiarra agora... mas não se preocupe, é apenas para facilitar a sua vida. Como as logs do Apache são geradas em um caminho onde os usuários comuns não tem acesso, vamos precisar alterar o _owner_ da instalação do seu Logstash para o "root". Caso contrário, teríamos que fazer algumas alterações no Apache ou/e em outras coisinhas chatas que só atrasariam o foco do nosso aprendizado e bla bla bla. Sendo assim, altera ai vai... tem ninguém olhando não: 49 | 50 | ``` 51 | $ ls -ltr 52 | drwxr-xr-x. 12 alefeans alefeans 4096 dez 4 05:57 kibana-5.6.5-linux-x86_64 53 | drwxr-xr-x. 9 alefeans alefeans 4096 jan 9 13:47 elasticsearch-5.6.5 54 | drwxr-xr-x. 12 alefeans alefeans 4096 jan 16 12:40 logstash-5.6.5 55 | 56 | $ sudo chown -R root:root logstash-5.6.5/ 57 | $ ls -ltr 58 | drwxr-xr-x. 12 alefeans alefeans 4096 dez 4 05:57 kibana-5.6.5-linux-x86_64 59 | drwxr-xr-x. 9 alefeans alefeans 4096 jan 9 13:47 elasticsearch-5.6.5 60 | drwxr-xr-x. 12 root root 4096 jan 16 12:40 logstash-5.6.5 61 | 62 | ``` 63 | 64 | Agora, vá até o diretório "/bin" da instalação do Logstash e execute o comando abaixo para iniciá-lo. Não se esqueça de executá-lo com o usuário __"root"__: 65 | 66 | ``` 67 | nohup ./logstash -f ../config/logstash-apache.conf & 68 | ``` 69 | 70 | Utilizamos o parâmetro "-f" para informar ao Logstash o arquivo de configuração que criamos. Feito isso, vamos validar o nosso index "apache" no Kibana: 71 | 72 | ![](/gifs/apache_index.gif) 73 | 74 | Agora conseguimos visualizar todas as requisições feitas ao nosso servidor Web pelo Kibana ! Caso você não esteja visualizando nenhum dado, certifique-se de alterar o filtro de tempo no canto superior direito, ajustando com a data em que a entrada dos dados foi feita. É interessante também configurar um refresh automático para visualizar a entrada dos dados em real-time. 75 | 76 | Faça algumas requisições ao seu Apache acessando o endereço http://localhost:80 e http://localhost:80/bla (para forçarmos um erro em nossas logs) ou simplesmente execute o script [requests.sh](/scripts/requests.sh), para gerarmos uma massa de dados em nosso index: 77 | 78 | ``` 79 | nohup ./requests.sh & 80 | ``` 81 | 82 | __OBS:__ O script está apontando para o endereço __localhost__, então caso esteja utilizando mais de um servidor para as atividades deste repositório, certifique-se de executá-lo no servidor onde o seu Apache está executando. 83 | 84 | __OBS²:__ Executamos o script em background, pois o mesmo demora um pouquinho para finalizar sua execução. Caso queira aumentar a massa de dados, é só repetir a sua execução. 85 | 86 | Próximo: [Pesquisas no Kibana](/pages/kibana_searches.md) 87 | -------------------------------------------------------------------------------- /pages/node_cluster.md: -------------------------------------------------------------------------------- 1 | ## Node e Cluster 2 | 3 | Lembra que eu havia dito que o Elasticsearch foi feito para o _Cloud Computing_ ? Nos próximos tópicos, explicarei como a redundância e a alta disponibilidade são tratadas internamente pela ferramenta através de alguns conceitos de _clusterização_ e replicação de dados. Esses conceitos são essenciais para entendermos a ferramenta mais a fundo e para comprovarmos a sua fácil adequação à um ambiente em nuvem. 4 | 5 | Um __node__ é uma instância em execução de Elasticsearch, enquanto um __cluster__ consiste em um ou mais nodes trabalhando em conjunto, como se fossem uma só instância. Instâncias em um mesmo cluster compartilham do mesmo _cluster name_ e possuem uma organização que permite que mais instâncias sejam adicionadas ou removidas ao cluster sem prejudicar o armazenamento dos dados. Afinal, em um ambiente em _cloud_, é comum servidores serem adicionados ou descartados a todo momento e isso de forma alguma pode impactar a disponibilidade do serviço ou a integridade dos dados. 6 | 7 | Em um cluster de Elasticsearch, sempre teremos uma instância declarada como node _master_, o que signficia que esta instância é responsável por lidar com alterações abrangentes que venham a modificar informações à nível de cluster (ex: criação/remoção de um index, adição de nodes ao cluster e etc). Pequenas alterações à nível de documento não exigem a participação do node master, sendo assim, ter apenas um node master em seu cluster _pode ser_ o suficiente. O interessante é que nós usuários podemos interagir com __qualquer__ node do cluster de forma transparente para realizarmos as operações comuns (inclusão, pesquisa, remoção e etc). 8 | 9 | No nosso caso, temos apenas uma instância de Elasticsearch em execução, o que significa que nosso cluster possui apenas um node e que, obviamente, é o node master. Vamos utilizar abaixo a API **_cluster** para verificarmos a saúde do nosso ambiente: 10 | 11 | ``` 12 | curl -XGET http://localhost:9200/_cluster/health?pretty 13 | ``` 14 | 15 | O campo status utiliza de cores básicas para indicar a saúde do nosso cluster: 16 | 17 | __Green__: Todos os shards primários e replicas estão ativos. 18 | 19 | __Yellow__: Todos os shards primários estão ativos, mas nem todas as réplicas estão. 20 | 21 | __Red__: Nem todos os shards estão ativos. 22 | 23 | Você deve estar pensando "E o que isso signficia se eu nem sei o que é um shard ?". Vamos tentar entender isto melhor agora... 24 | 25 | Próximo: [Shards e Replicas](/pages/shards_replicas.md) 26 | -------------------------------------------------------------------------------- /pages/rest_json.md: -------------------------------------------------------------------------------- 1 | ## REST e JSON 2 | 3 | Legal, mas o que realmente aconteceu aqui ? Lembra que o Elasticsearch possui uma API RESTful ? Lembra o que é API RESTful ? Lembra o que é REST ? Não ? Que vergonha... 4 | 5 | Falando da forma mais simples possível, uma API RESTful é uma API que faz/aceita chamadas REST e REST, representa um conjunto de operações padronizadas que permitem a troca de informação entre sistemas através de simples métodos HTTP. 6 | 7 | No exemplo anterior, fizemos uma chamada __REST__ solicitando uma resposta para o nosso Elasticsearch através do método HTTP __GET__ e como retorno à nossa requisição, recebemos uma resposta no formato __JSON__ com algumas informações básicas sobre a nossa instância de Elasticsearch. 8 | 9 | Sempre usaremos o formato JSON ao trabalharmos com o Elasticsearch, tanto para enviar requisições, quanto no recebimento das respostas. 10 | 11 | Sobre o JSON, imagine que você precisa fazer duas aplicações totalmente distintas se comunicarem entre si. Como fazer essa troca de informação ? O JSON por ser um formato padrão aceito pela maioria das linguagens de programação, pode ser utilizado para garantir que as duas aplicações possam "entender" o que a outra está querendo dizer de forma mais simples e legível se comparada com outros padrões (como o _XML_, por exemplo). Vamos ver como este padrão funciona ? 12 | 13 | ``` 14 | { # Abertura de sequência. 15 | # O padrão é: "campo" ":" e "valor". 16 | # Caso hajam vários campos, colocar uma "," no final. 17 | "nome": "John Will", # Strings precisam estar entre aspas. 18 | "idade": 19, # Inteiros são apresentados sem aspas. 19 | "deficiente": True, # Booleanos são bem-vindos. 20 | "interesses": [ "musica", # Arrays sao representados entre "[]". 21 | "esportes"] 22 | } # Fechamento da sequência. Fim do documento JSON. 23 | ``` 24 | 25 | Agora que sabemos como criar um _documento_ JSON, vamos entender a sintaxe utilizada para as chamadas REST: 26 | 27 | ``` 28 | curl -X '://:/?' -d '' 29 | ``` 30 | 31 | O __curl__ é uma ferramenta para transferência de dados através de uma URL. Usaremos ela para efetuarmos nossas requisições ao Elasticsearch. Segue a explicação para os demais campos: 32 | 33 | __VERB__ -> GET, POST, PUT, DELETE. 34 | 35 | __PROTOCOLO__ -> http, https... 36 | 37 | __HOST__ -> Servidor do Elasticsearch. 38 | 39 | __PORTA__ -> Porta do Elasticsearch (9200 é a porta padrão). 40 | 41 | __PATH__ -> Aonde você quer pesquisar, atualizar, incluir ou deletar (qual o _index_, _type_ e _document id_ ?). 42 | 43 | __QUERY_STRING__ -> A pesquisa propriamente dita. 44 | 45 | __BODY__ -> O documento JSON que você quer enviar ou utilizar como parâmetro de pesquisa. 46 | 47 | Próximo: [Index, Type e Document ?](/pages/index_type_document.md) 48 | -------------------------------------------------------------------------------- /pages/shards_replicas.md: -------------------------------------------------------------------------------- 1 | ## Shards e Replicas 2 | 3 | Quando indexamos nossos documentos no Elasticsearch (lembre-se do significado de _indexar_ explicado anteriormente), estamos adicionando nossos dados em um __shard__, que são basicamente "containers" que armazenam os dados que indexamos no Elasticsearch. Porém, nossas aplicações não falam diretamente com o shard em si, mas sim com os índices. A realidade é que os índices, "mycompany" ou "twitter" por exemplo, são apenas _"caminhos lógicos"_ ou _"namespaces"_, que apontam para um ou mais __shards__. Ou seja, quando realizamos uma inserção de um documento em um index no Elasticsearch, passamos o caminho do index que queremos utilizar, e este, fará o armazenamento do documento em algum shard qualquer, de forma balanceada. 4 | 5 | Após o direcionamento para um shard, o Apache Lucene entra em ação. Dentro de cada shard há uma instância de Lucene em execução, utilizando o seu motor de busca e indexação para acessar/armazenar os nossos dados. Isso nos garante toda a inteligência e velocidade que esta biblioteca possui na busca de documentos. 6 | 7 | Vamos executar um comando que utilizamos no inicio deste repositório para validarmos a quantidade de índices criados e consultarmos algumas informações sobre os nossos shards: 8 | 9 | ``` 10 | curl -XGET http://localhost:9200/_cat/indices?v 11 | ``` 12 | 13 | Provavelmente você recebeu um retorno parecido com este (formatei em tabela para melhorar a visualização): 14 | 15 | | health| status | index | uuid | pri | rep | docs.count| docs.deleted| store.size| pri.store.size| 16 | | ----- |--------|----- |------|----- |--------|----- |--------|----|:------:| 17 | |yellow | open | mycompany | pUEvAXsjQIm | 5 | 1 | 3 | 0| 17.8kb | 17.8kb | 18 | |yellow | open | twitter | LKz87NMtTlShp | 5 | 1 | 14 | 0| 29.9kb | 29.9kb | 19 | 20 | Quando iniciamos uma instância de Elasticsearch, por default são criados 5 shards (coluna __pri__, que significa "primary"), com 1 réplica por shard (coluna __rep__, que significa "replica"). A medida que adicionamos mais instâncias em nosso cluster, os shards são replicados/migrados entre os nodes pelo próprio Elasticsearch, que fará o possível para manter o nosso cluster balanceado. Um shard _primary_ possui a função de armazenar todos os documentos do seu index. Já um shard _replica_, garante a redundância dos seus dados, servindo como uma cópia do seu shard primary e também, respondendo à requisições de leitura/busca de documentos. 21 | 22 | Avaliando a tabela com o resultado do nosso comando, vemos que o "health" do nosso cluster está em "yellow", certo ? Isso se deve ao fato de possuirmos cinco shards primários armazenando nossos dados em um mesmo node, e a perda de um deles, seja por uma falha de hardware por exemplo, pode resultar em uma perda real de dados. Veja a imagem abaixo para entender melhor em que cenário o nosso cluster se encontra: 23 | 24 | ![](/images/five_shards.png) 25 | 26 | __Legenda__: P = Primary. 27 | 28 | __OBS:__ Na realidade, nosso cluster possui 10 shards primários, já que possuímos 2 index diferentes (mycompany e twitter). Na imagem acima, considere que estamos visualizando apenas os shards de um único index, que pode ser qualquer um dos dois que possuímos em nosso ambiente. 29 | 30 | Mas aonde estão as nossas réplicas ? Execute o comando utilizado para verificar a saúde do cluster novamente (.../_cluster/health?pretty) e observe o retorno do comando. Veja que há um campo chamado, __"unassigned_shards"__ com o valor 10. Isso significa que possuímos 10 shards que não estão associados à nenhum node de Elasticsearch e esses shards, são exatamente as nossas réplicas. Lembre-se, por default o Elasticsearch cria 5 shards primários e 1 réplica por shard quando criamos um index. O número de réplicas sempre estará associado ao número de shards primários, ou seja, possuímos 1 réplica para cada shard (5 * 1 = 5), e como possuímos dois index, dobramos este valor (5 * 2 = 10). 31 | 32 | __OBS:__ Caso seja necessário, valide os resultados acima utilizando uma calculadora. 33 | 34 | Pense na estratégia adotada pelo Elasticsearch em não associar nenhuma réplica ao nosso node. Faz todo o sentido ! Não há nenhuma vantagem em armazenar as cópias dos mesmos dados em um mesmo node, pois caso venhamos a perder este node, tanto a cópia quanto a "original" seriam comprometidas. Sendo assim, o status do nosso cluster é classificado como "yellow" e permanecerá assim até adicionarmos novos nodes em nosso cluster e termos nossas réplicas balanceadas entre eles. 35 | 36 | Para termos uma melhor visualização nos próximos passos, vamos deletar os nossos índices "mycompany" e "twitter". Sim eu sei que é doloroso, _but we have to do it_: 37 | 38 | ``` 39 | curl -XDELETE http://localhost:9200/mycompany,twitter 40 | ``` 41 | 42 | __OBS:__ Veja que podemos apagar mais de um index em um só comando, separando-os por vírgula. _Wildcards_ também são aceitos como parâmetro (Ex: \*, ?, e etc), porém não são recomendados devido a grande capacidade que temos de fazer alguma merda ao utilizá-los. 43 | 44 | O número de shards primários é fixado no momento da criação do index, enquanto a quantida de réplicas pode ser alterada a qualquer momento. Vamos criar um novo index chamado "market" e alterar a quantidade de shards primários que serão criados pelo Elasticsearch: 45 | 46 | ``` 47 | curl -XPUT http://localhost:9200/market -d ' 48 | { 49 | "settings" : { 50 | "index" : { 51 | "number_of_shards" : 3, 52 | "number_of_replicas" : 1 53 | } 54 | } 55 | }' 56 | ``` 57 | 58 | Legal, se chamarmos novamente a API \_cluster para verificarmos a saúde novamente, estaremos vendo algo parecido com isso: 59 | 60 | ``` 61 | { 62 | "cluster_name" : "elasticsearch", 63 | "status" : "yellow", 64 | "timed_out" : false, 65 | "number_of_nodes" : 1, 66 | "number_of_data_nodes" : 1, 67 | "active_primary_shards" : 3, 68 | "active_shards" : 3, 69 | "relocating_shards" : 0, 70 | "initializing_shards" : 0, 71 | "unassigned_shards" : 3, 72 | "delayed_unassigned_shards" : 0, 73 | "number_of_pending_tasks" : 0, 74 | "number_of_in_flight_fetch" : 0, 75 | "task_max_waiting_in_queue_millis" : 0, 76 | "active_shards_percent_as_number" : 50.0 77 | } 78 | ``` 79 | 80 | Temos agora 3 shards primários ativos e 3 shards desassociados, como esperávamos. Vamos adicionar mais um node de Elasticsearch em nosso cluster para resolvermos essa questão de "alta disponibilidade" (leia com a voz que você faz quando está debochando de alguém). Sem precisar alterar nada, vá até o diretório "bin/" da instalação do seu Elasticsearch e execute o comando de subida da instância, conforme abaixo: 81 | 82 | ``` 83 | nohup ./elasticsearch -Epath.data=data2 -Epath.logs=log2 & 84 | ``` 85 | 86 | __OBS:__ Não se esqueça de validar o quanto de memória disponível você possui no seu servidor, pois iremos subir uma nova instância de Elasticsearch que irá consumir em média 2gb~2,5gb de memória. Também não se preocupe se não possuir esta quantidade disponível, pois isso não impedirá a realização dos passos subsequentes do nosso treinamento :). 87 | 88 | O comando acima simplesmente inicia uma nova instância de Elasticsearch informando um caminho diferente para o armazenamento dos dados (_-Epath.data=data2_) e um outro diretório para o armazenamento de logs (_-Epath.logs=log2_). Veja que agora os dois novos diretórios foram criados no diretório que o comando foi executado: 89 | 90 | ``` 91 | $ ls -ltr | grep ^d 92 | drwxrwxr-x. 2 alefeans alefeans 4096 jan 11 16:20 log2 93 | drwxrwxr-x. 3 alefeans alefeans 4096 jan 11 16:20 data2 94 | ``` 95 | 96 | Caso queira alterar para um outro caminho de sua preferência, sinta-se a vontade e passe o caminho completo do diretório como parâmetro. Vamos verificar o status do nosso cluster agora ? Chama aquela API que mostra o status do seu cluster você já está cansado de usar e veja se o resultado está parecido com este: 97 | 98 | ``` 99 | { 100 | "cluster_name" : "elasticsearch", 101 | "status" : "green", 102 | "timed_out" : false, 103 | "number_of_nodes" : 2, 104 | "number_of_data_nodes" : 2, 105 | "active_primary_shards" : 3, 106 | "active_shards" : 6, 107 | "relocating_shards" : 0, 108 | "initializing_shards" : 0, 109 | "unassigned_shards" : 0, 110 | "delayed_unassigned_shards" : 0, 111 | "number_of_pending_tasks" : 0, 112 | "number_of_in_flight_fetch" : 0, 113 | "task_max_waiting_in_queue_millis" : 0, 114 | "active_shards_percent_as_number" : 100.0 115 | } 116 | ``` 117 | 118 | Olha que legal, agora o nosso cluster está com o status "green", possuimos um "number_of_nodes" de 2, temos 6 "active_shards" e nenhum "unassigned_shards". Apesar de estarmos utilizando o mesmo hardware (o que não garante nenhuma alta disponibilidade real), por possuirmos 2 nodes em nosso cluster, o Elasticsearch já o considera como "green" por conta da distribuição dos shards primários e réplicas. 119 | 120 | Mas vamos lá ... como esta nova instância _simplesmente_ começou a fazer parte do meu cluster ? E como minhas replicas e shards foram distribuidas pelo Elasticsearch ? 121 | 122 | Pois bem, o Elasticsearch em sua configuração padrão vem com o cluster_name __"elasticsearch"__ e ao ser iniciado, ele realiza a busca por um node master em sua máquina local. Ao subirmos esta outra instância com a mesma configuração, ele buscou por estas informações em seu host e pronto, começou a fazer parte do nosso cluster. 123 | 124 | Se quisessemos configurar um node de Elasticsearch em uma máquina remota para fazer parte do nosso cluster, teríamos que configurar alguns parâmetros a mais (endereço do servidor remoto, node name e etc), em seu arquivo de configuração principal: **config/elasticsearch.yml**. Mas isto não vem ao caso agora. Quer saber como os seus shards estão balanceados entre os seus nodes agora ? Veja a imagem abaixo: 125 | 126 | ![](/images/two_nodes.png) 127 | 128 | __Legenda:__ P = Primary; R = Replica. 129 | 130 | Agora possuímos todas as nossas réplicas associadas ao nosso node 2. Perceba que qualquer requisição pode ser atendida por qualquer node, já que possuímos exatamente __todos__ os dados replicados em todos os nodes de nosso cluster. Para uma última ilustração, caso tivessemos 3 nodes e 2 réplicas, nosso cluster estaria representado mais ou menos desta forma: 131 | 132 | ![](/images/three_nodes.png) 133 | 134 | 135 | Caso haja uma falha em qualquer um dos nodes, temos a garantia de que qualquer outro node restante será capaz de responder a qualquer tipo de requisição de inserção/leitura de documentos. 136 | 137 | Existem diversas configurações que podem ser feitas e melhoradas em um ambiente produtivo real à respeito de cluster, shards e replicas, mas este não é o foco deste repositório. Mais informações à respeito de configurações, redundância e performance, são encontradas facilmente na documentação oficial da Elastic. 138 | 139 | 140 | Próximo: [Inverted Index](/pages/inverted_index.md) 141 | -------------------------------------------------------------------------------- /pages/shutdown.md: -------------------------------------------------------------------------------- 1 | ## Tudo muito fácil. O que mais eu posso fazer ? 2 | 3 | Agora que entendemos sobre as formas e os tipos de pesquisa de forma básica, vamos aprender mais alguns comandos e funcionalidades utilizando as APIs do Elasticsearch, antes de partirmos para o Logstash e o Kibana. 4 | 5 | #### Shutdown 6 | 7 | Depois de tanto tempo no ar, vamos dar um descanço pro cara né ? Para finalizar o seu Elasticsearch, você pode OU pará-lo via __service management__ utilizando, por exemplo, o comando "_sudo systemctl stop elasticsearch_" OU enviando executando um `kill` no PID do seu processo. Como fizemos a instalação diretamente do .zip, usaremos a segunda forma: 8 | 9 | ``` 10 | $ jps | grep Elasticsearch 11 | 22223 12 | $ kill 22223 13 | ``` 14 | 15 | Ou se você for mais _oldschool_: 16 | 17 | ``` 18 | $ ps -ef | grep -i elasticsearch | grep -v grep | awk '{print $2}' 19 | 22223 20 | $ kill 22223 21 | ``` 22 | 23 | Próximo: [Contagem de Documentos](/pages/counting.md) 24 | -------------------------------------------------------------------------------- /pages/stack.md: -------------------------------------------------------------------------------- 1 | ## Avançando na Stack 2 | 3 | Estamos há um bom tempo falando somente sobre o Elasticsearch e há um motivo especial para isso. Ele é o coração da nossa stack. É essencial compreendermos bem o seu funcionamento para não haver nenhuma dúvida na hora de pesquisarmos nossos documentos ou quando começarmos a criar nossos dashboards no Kibana. 4 | 5 | #### Instalação - Logstash e Kibana 6 | 7 | Agora, chega de enrolação ! Vamos realizar a instalação da mesma forma que instalamos o Elasticsearch, realizando o download do _.zip_ do [Kibana](https://www.elastic.co/downloads/kibana) e do [Logstash](https://www.elastic.co/downloads/logstash), realizando o unzip em um diretório separado para cada um deles e pronto. Fácil né ? Elastic né filho... 8 | 9 | __OBS:__ Pode ser que não haja nenhum problema de compatibilidade, mas lembre-se que estamos utilizando a versão 5.6.5 para todas as ferramentas da stack neste repositório. Não se esqueça também de validar a quantidade de memória disponível do seu host para a subida do Kibana. 10 | 11 | Agora, entre no diretório da instalação do Kibana e navegue até o diretório _bin_. Execute o comando abaixo para subir uma instância: 12 | 13 | ``` 14 | nohup ./kibana & 15 | ``` 16 | 17 | Após a subida do processo, acesse o endereço http://localhost:5601 no seu browser. 18 | 19 | __OBS:__ Caso esteja utilizando uma máquina virtual, utilizar o endereço de IP da sua vm ao invés de _localhost_. 20 | 21 | [Kibana](/pages/kibana.md) 22 | -------------------------------------------------------------------------------- /pages/structured.md: -------------------------------------------------------------------------------- 1 | ## Estruturada 2 | 3 | Uma pesquisa estruturada diz respeito à pesquisas que possuem algum tipo de parametrização/regra envolvida. Para este exemplo, vamos usar o script [funcs.sh](/scripts/funcs.sh) para gerar mais dados no nosso _esquecido_ índice "mycompany". 4 | 5 | Após executar o script, faça a pesquisa estruturada abaixo. Tente interpretá-la juntamente com o seu resultado antes de ler a explicação, ok ? 6 | 7 | ``` 8 | curl -XGET http://localhost:9200/mycompany/_search\?pretty -d ' 9 | { 10 | "query": { 11 | "bool": { 12 | "must": { 13 | "match": { 14 | "nome": "Silva" 15 | } 16 | }, 17 | "filter": { 18 | "range": { 19 | "idade": { 20 | "gt": 30 21 | } 22 | } 23 | } 24 | } 25 | } 26 | } 27 | ' 28 | ``` 29 | 30 | E ai, conseguiu ? Se a resposta for não, fique tranquilo, algumas coisas novas apareceram por aqui. Vamos entendê-las melhor: 31 | 32 | __1°__ - Iniciamos o parâmetro "query". 33 | 34 | __2°__ - O parâmetro de busca "bool" inicia uma combinação de resultados entre queries, indicando um ou mais filtros à serem respeitados. 35 | 36 | __3°__ - O **"must"** é um parâmetro de "bool" que significa que o valor __DEVE__ ser encontrado em todos os resultados. Isto contribui para um **_score** mais preciso. 37 | 38 | __4°__ - Dentro da cláusula "must" temos o parâmetro "match" já usado para pesquisas mais simples. Este tem a simples tarefa de relacionar um campo com um valor. 39 | 40 | __5°__ - Perceba que há uma "**,**" antes do parâmetro **"filter"**. Em JSON, a vírgula faz a separação de múltiplos campos. Estamos passando duas cláusulas para o parâmetro "bool" avaliar: **"must"** e **"filter"**, sendo assim, precisamos separá-los por vírgula. 41 | 42 | __6°__ - Dentro de "filter", passamos um "range" para o nosso campo "idade", que neste caso, deve ser maior que 30 (**gt** = greater than). 43 | 44 | Após compreendermos cada passo, a tradução final da query para a nossa linguagem seria esta: 45 | _"Elasticsearch, quais são os funcionários com mais de 30 anos que tem Silva no nome ?"_ 46 | 47 | A medida que as pesquisas se tornam maiores e mais específicas, mais campos e parâmetros são encadeados para satisfazer as condições da busca. Existem diversos argumentos disponíveis para a refinação de queries que são facilmente encontrados na documentação da [Elastic](https://www.elastic.co/guide/index.html). Alguns serão abordados mais a frente, após aprendermos o básico sobre os tipos de busca. 48 | 49 | Próximo: [Analítica](/pages/analytics.md) 50 | -------------------------------------------------------------------------------- /pages/types_forms.md: -------------------------------------------------------------------------------- 1 | ## Tipos e Formas de Pesquisa 2 | 3 | Agora, vamos entender os três _tipos_ de pesquisa que existem no Elasticsearch (full-text, estruturada e analítica) e as duas _formas_ básicas de construção de pesquisas (query-string e query DSL). 4 | 5 | Para este exemplo, utilize o script [tweets.sh](/scripts/tweets.sh) para criar o index _twitter_ que irá conter diversos tweets de usuários diferentes. Após a execução do script, visualize os índices existentes no seu Elasticsearch utilizando a API **_cat**: 6 | 7 | ``` 8 | curl -XGET http://localhost:9200/_cat/indices?v 9 | ``` 10 | 11 | Não se preocupe com todas as informações retornadas (nem se estiver com seus índices com o "health" em "yellow"), tome por nota apenas a informação dos índices que você possui (mycompany e twitter). Agora que geramos a massa de dados, vamos as queries ! 12 | 13 | Primeiro, vamos ver como a query-string funciona. Vamos pesquisar todos os tweets do usuário "Phill": 14 | 15 | ``` 16 | curl -XGET http://localhost:9200/twitter/tweet/_search?q=name:Phill 17 | ``` 18 | 19 | Apesar de parecer bastante simples de se utilizar, esse formato é o menos utilizado. A medida que colocamos mais parâmetros e condições, a busca começa a aparecer mais complicada do que realmente é. Por exemplo, vamos pesquisar pelo nome "Tom" no campo "name" __e__ "lina" no campo "tweet": 20 | 21 | ``` 22 | curl -XGET http://localhost:9200/twitter/tweet/_search?q=%2Bname%3Atom+%2Btweet%3Alina 23 | ``` 24 | 25 | Perceba que mesmo sendo uma pesquisa relativamente simples, a string de pesquisa se tornou um pouco menos _legível_. Agora, vamos realizar a primeira pesquisa feita no index twitter anteriormente, utilizando a __query DSL__: 26 | 27 | ``` 28 | curl -XGET http://localhost:9200/twitter/tweet/_search?pretty -d ' 29 | { 30 | "query": { 31 | "match": { "name": "Phill" } 32 | } 33 | }' 34 | ``` 35 | 36 | Neste formato, passamos um documento JSON como parâmetro de pesquisa. Antes de mais nada, vamos entender o que nos é retornado quando realizamos uma pesquisa. Utilizando o exemplo de retorno da query acima, temos o resultado abaixo: 37 | 38 | ``` 39 | { 40 | "took" : 8, # Tempo em milissegundos que a query demorou para retornar. 41 | "timed_out" : false, # Houve Time Out na busca (True or False) ? 42 | "_shards" : { # Falaremos sobre shards mais tarde... 43 | "total" : 5, 44 | "successful" : 5, 45 | "failed" : 0 46 | }, 47 | "hits" : { 48 | "total" : 1, # Quantidade de documentos que foram encontrados. 49 | "max_score" : 0.25811607, # Falaremos sobre score mais tarde também... 50 | "hits" : [ # Dentro deste array, possuímos todos os resultados encontrados. 51 | { 52 | "_index" : "twitter", # Qual o index do documento. 53 | "_type" : "tweet", # Qual o type do documento. 54 | "_id" : "14", # Qual o id do documento. 55 | "_score" : 0.25811607, # Ó o score ai denovo... 56 | "_source" : { # Todos os dados do documento encontrado: 57 | "date" : "2018-09-23", 58 | "name" : "Phill Matt", 59 | "tweet" : "Just one is sufficient.", 60 | "user_id" : 3 61 | } 62 | } 63 | ] 64 | } 65 | } 66 | ``` 67 | 68 | Inicialmente pode parecer estranho ou até um pouco frustrante ter que decifrar um documento JSON. Você tem que parar, analisar, entender o que está dentro de uma tag ou de outra... mas a medida que vamos praticando e brincando mais com o Elasticsearch, esta tarefa vai se tornando menos dolorosa ("_if it hurts, do it more often_", Martin Fowler). E relaxa, daqui a pouco estaremos usando o Kibana para nos ajudar nesta tarefa :) 69 | 70 | Agora vamos aos três tipos básicos de pesquisa... 71 | 72 | Próximo: [Full-text](/pages/full-text.md) 73 | -------------------------------------------------------------------------------- /pages/updating.md: -------------------------------------------------------------------------------- 1 | ## Atualizando 2 | 3 | Documentos no Elasticsearch são entidades _imutáveis_. Caso haja a necessidade de atualizar um documento existente, nós o _reindexamos_ ou o substituimos completamente, utilizando a mesma API que usamos para inserir um documento. Vamos alterar o endereço da funcionária "Maria" de id "2": 4 | 5 | ``` 6 | curl -XPUT http://localhost:9200/mycompany/funcionarios/2 -d ' 7 | { 8 | "nome": "Maria Costa", 9 | "idade": 34, 10 | "endereco": "Avenida do Amor", 11 | "hobbies": ["Ouvir musica", "Andar de bicicleta"], 12 | "interesses": ["esportes", "musica"] 13 | }' 14 | ``` 15 | 16 | Observe a resposta do Elasticsearch ao seu comando: 17 | 18 | ``` 19 | {"_index":"mycompany","_type":"funcionarios","_id":"2","_version":2,"result":"updated","_shards":{"total":2,"successful":1,"failed":0},"created":false}% 20 | ``` 21 | 22 | Podemos ver que o campo **"_version"** foi incrementado e que o campo **"created"** possui o valor _false_ (pois o documento que atualizamos já existia anteriormente). Por debaixo dos panos, o Elasticsearch marca o documento antigo como removido e adiciona o novo documento inteiro. 23 | 24 | Existe uma forma de realizar atualizações parciais utilizando a API **_update**. Este tipo de atualização também segue a mesma regra descrita para o update total, diferenciando-se apenas no fato de que é possivel atualizar os campos necessários sem precisar digitar o documento inteiro como parâmetro. Por exemplo: 25 | 26 | ``` 27 | curl -XPOST http://localhost:9200/mycompany/funcionarios/2/_update -d ' 28 | { 29 | "doc": { 30 | "idade": 35 31 | } 32 | }' 33 | ``` 34 | 35 | Podemos utilizar esta mesma API para acrescentarmos mais campos em nossos documentos. Faça o teste, altere o campo __"idade" : 35__ por um campo que não exista no nosso documento, atribuia um valor de sua preferência e acrescente-o no documento acima. 36 | 37 | Próximo: [Node e Cluster](/pages/node_cluster.md) 38 | -------------------------------------------------------------------------------- /pages/views.md: -------------------------------------------------------------------------------- 1 | ## Criando Views 2 | 3 | Vamos criar algumas views personalizadas para entender como estas se comportam e assim, utilizá-las para compor o nosso dashboard final. Não se atente aos dados que estamos pesquisando. Embora contabilizar a quantidade de retornos "200" e "404" seja importante, o objetivo deste tópico é fornecer uma visão geral do mecanismo de criação das views: 4 | 5 | 6 | Line View: 7 | 8 | ![](/gifs/line_view.gif) 9 | 10 | Metric View: 11 | 12 | ![](/gifs/metric_view.gif) 13 | 14 | Pie View: 15 | 16 | ![](/gifs/pie_view.gif) 17 | 18 | Area View: 19 | 20 | ![](/gifs/area_view.gif) 21 | 22 | Gauge View: 23 | 24 | ![](/gifs/gauge_view.gif) 25 | 26 | Bar View: 27 | 28 | ![](/gifs/bars_view.gif) 29 | 30 | Finalizada a criação das views, vamos criar o nosso primeiro dashboard ! 31 | 32 | Próximo: [Nosso primeiro Dashboard](/pages/dashboard.md) 33 | -------------------------------------------------------------------------------- /scripts/funcs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | curl -XPUT http://localhost:9200/mycompany/funcionarios/2 -d ' 3 | { 4 | "nome": "Maria Costa", 5 | "idade": 34, 6 | "endereco": "Rua da Frente", 7 | "hobbies": ["Ouvir musica", "Andar de bicicleta"], 8 | "interesses": ["esportes", "musica"] 9 | }' 10 | 11 | curl -XPUT http://localhost:9200/mycompany/funcionarios/3 -d ' 12 | { 13 | "nome": "José Cardoso", 14 | "idade": 28, 15 | "endereco": "Rua de Trás", 16 | "hobbies": "Ir para a academia", 17 | "interesses": ["esportes", "musculacao"] 18 | }' 19 | 20 | 21 | curl -XPUT http://localhost:9200/mycompany/funcionarios/4 -d ' 22 | { 23 | "nome": "Claudio Silva", 24 | "idade": 31, 25 | "endereco": "Avenida do Meio", 26 | "hobbies": ["Jogar PS4", "Programar"], 27 | "interesses": ["filmes", "games"] 28 | }' 29 | -------------------------------------------------------------------------------- /scripts/requests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for i in $(seq 50); do 4 | curl -i -o /dev/null localhost/icons/apache_pb2.gif 5 | sleep 1 6 | for x in $(( ( RANDOM % 10 ) + 1 )); do 7 | curl -s localhost:80/bla > /dev/null 8 | done; 9 | for y in $(( ( RANDOM % 10 ) + 1 )); do 10 | sleep 1 11 | curl -i -o /dev/null localhost/icons/apache_pb2.gif 12 | done; 13 | done; 14 | 15 | -------------------------------------------------------------------------------- /scripts/tweets.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | curl -XPOST http://localhost:9200/_bulk -d ' 3 | 4 | { "create": { "_index": "twitter", "_type": "user", "_id": "1" }} 5 | { "email" : "tom@smith.com", "name" : "Tom Michael", "username" : "@tom" } 6 | { "create": { "_index": "twitter", "_type": "user", "_id": "2" }} 7 | { "email" : "lina@jones.com", "name" : "Lina Jones", "username" : "@lina" } 8 | { "create": { "_index": "twitter", "_type": "tweet", "_id": "3" }} 9 | { "date" : "2018-09-13", "name" : "Lina Jones", "tweet" : "Elasticsearch means full text search has never been so easy", "user_id" : 2 } 10 | { "create": { "_index": "twitter", "_type": "tweet", "_id": "4" }} 11 | { "date" : "2018-09-14", "name" : "Tom Michael", "tweet" : "@lina it is not just text, it does everything", "user_id" : 1 } 12 | { "create": { "_index": "twitter", "_type": "tweet", "_id": "5" }} 13 | { "date" : "2018-09-15", "name" : "Lina Jones", "tweet" : "However did I manage before Elasticsearch?", "user_id" : 2 } 14 | { "create": { "_index": "twitter", "_type": "tweet", "_id": "6" }} 15 | { "date" : "2018-09-16", "name" : "Tom Michael", "tweet" : "The Elasticsearch API is really easy to use", "user_id" : 1 } 16 | { "create": { "_index": "twitter", "_type": "tweet", "_id": "7" }} 17 | { "date" : "2018-09-17", "name" : "Lina Jones", "tweet" : "The Query DSL is really powerful and flexible", "user_id" : 2 } 18 | { "create": { "_index": "twitter", "_type": "tweet", "_id": "8" }} 19 | { "date" : "2018-09-18", "name" : "Tom Michael", "user_id" : 1 } 20 | { "create": { "_index": "twitter", "_type": "tweet", "_id": "9" }} 21 | { "date" : "2018-09-19", "name" : "Lina Jones", "tweet" : "Geo-location aggregations are really cool", "user_id" : 2 } 22 | { "create": { "_index": "twitter", "_type": "tweet", "_id": "10" }} 23 | { "date" : "2018-09-20", "name" : "Tom Michael", "tweet" : "Elasticsearch surely is one of the hottest new NoSQL products", "user_id" : 1 } 24 | { "create": { "_index": "twitter", "_type": "tweet", "_id": "11" }} 25 | { "date" : "2018-09-21", "name" : "Lina Jones", "tweet" : "Elasticsearch is built for the cloud, easy to scale", "user_id" : 2 } 26 | { "create": { "_index": "twitter", "_type": "tweet", "_id": "12" }} 27 | { "date" : "2018-09-22", "name" : "Tom Michael", "tweet" : "Elasticsearch and I have left the honeymoon stage, and I still love her.", "user_id" : 1 } 28 | { "create": { "_index": "twitter", "_type": "tweet", "_id": "13" }} 29 | { "date" : "2018-09-23", "name" : "Tom Michael", "tweet" : "So yes, I am an Elasticsearch fanboy", "user_id" : 2 } 30 | { "create": { "_index": "twitter", "_type": "tweet", "_id": "14" }} 31 | { "date" : "2018-09-24", "name" : "Phill Matt", "tweet" : "Just one is sufficient.", "user_id" : 3 } 32 | ' 33 | -------------------------------------------------------------------------------- /vagrant/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | Vagrant.configure("2") do |testing| 5 | testing.vm.box = "geerlingguy/centos7" 6 | testing.vm.hostname = "elastic" 7 | testing.vm.network "private_network", ip: "10.20.188.253" 8 | testing.vm.network "forwarded_port", guest: 80, host: 8080 9 | testing.vm.provider "virtualbox" do |testing| 10 | testing.customize [ "modifyvm", :id, "--cpus", "1" ] 11 | testing.customize [ "modifyvm", :id, "--memory", "512" ] 12 | end 13 | end 14 | --------------------------------------------------------------------------------