-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
2531 lines (2531 loc) · 236 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>C语言多线程编程 (一)</title>
<url>/2023/11/25/C%E8%AF%AD%E8%A8%80%E5%A4%9A%E7%BA%BF%E7%A8%8B-1/</url>
<content><![CDATA[<p>简单说明和使用C语言在window操作系统下创建多线程实现简单的示例操作。</p>
<span id="more"></span>
<h2 id="创建进程">创建进程</h2>
<p>使用的是<code>windows.h</code>提供的创建进程函数,如下:</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">start_caculator</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> DWORD dwExitCode;</span><br><span class="line"> PROCESS_INFORMATION pi;</span><br><span class="line"> DWORD ret;</span><br><span class="line"> STARTUPINFO si = { <span class="built_in">sizeof</span>(si) };</span><br><span class="line"></span><br><span class="line"> <span class="type">char</span> s[] = <span class="string">"calc.exe"</span>;</span><br><span class="line"> <span class="comment">// 启动计算机</span></span><br><span class="line"> <span class="comment">// C++不能字符串转换 修改工程属性 项目属性->高级->字符集->使用Unicode字符集改为未设置</span></span><br><span class="line"> ret = <span class="built_in">CreateProcess</span>(<span class="literal">NULL</span>, s, <span class="literal">NULL</span>, <span class="literal">NULL</span>, FALSE, <span class="number">0</span>, <span class="literal">NULL</span>, <span class="literal">NULL</span>, &si, &pi);</span><br><span class="line"> <span class="keyword">if</span> (ret) {</span><br><span class="line"> <span class="comment">// 等待子进程的退出</span></span><br><span class="line"> <span class="built_in">WaitForSingleObject</span>(pi.hProcess, INFINITE);</span><br><span class="line"> <span class="comment">// 关闭子进程的主线程语句</span></span><br><span class="line"> <span class="built_in">CloseHandle</span>(pi.hThread);</span><br><span class="line"> <span class="comment">// 获取子进程的退出码</span></span><br><span class="line"> <span class="built_in">GetExitCodeProcess</span>(pi.hProcess, &dwExitCode);</span><br><span class="line"> <span class="comment">// 关闭子进程句柄</span></span><br><span class="line"> <span class="built_in">CloseHandle</span>(pi.hProcess);</span><br><span class="line"> }</span><br><span class="line"> cout << <span class="string">"\n进程结束 退出码是"</span> << ret << endl;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>其中主要的是:</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line">ret = <span class="built_in">CreateProcess</span>(<span class="literal">NULL</span>, s, <span class="literal">NULL</span>, <span class="literal">NULL</span>, FALSE, <span class="number">0</span>, <span class="literal">NULL</span>, <span class="literal">NULL</span>, &si, &pi);</span><br></pre></td></tr></table></figure>
<p>参数说明:</p>
<ul>
<li>lpApplicationName: 指定要运行的可执行文件的名称。在这种情况下,使用NULL表示使用命令行参数中指定的可执行文件</li>
<li><strong>lpCommandLine: 指定要传递给可执行文件的命令行参数。在这种情况下,使用字符串变量s作为命令行参数。</strong></li>
<li>lpProcessAttributes: 指定新进程的安全描述符。在这种情况下,使用NULL表示使用默认的安全描述符。</li>
<li>lpThreadAttributes: 指定新线程的安全描述符。在这种情况下,使用NULL表示使用默认的安全描述符。</li>
<li>bInheritHandles: 指定是否继承父进程的句柄。在这种情况下,使用FALSE表示不继承句柄。</li>
<li>dwCreationFlags: 指定控制新进程创建方式的标志。在这种情况下,使用0表示默认创建方式。</li>
<li>lpEnvironment: 指定新进程的环境块。在这种情况下,使用NULL表示使用父进程的环境块。</li>
<li>lpCurrentDirectory: 指定新进程的当前工作目录。在这种情况下,使用NULL表示使用父进程的当前工作目录。</li>
<li><strong>lpStartupInfo: 指向一个STARTUPINFO结构,该结构包含了新进程的一些属性,例如窗口显示方式、标准输入输出重定向等。在这种情况下,使用si结构体。</strong></li>
<li><strong>lpProcessInformation: 指向一个PROCESS_INFORMATION结构,该结构接收新进程的标识信息,例如进程句柄和线程句柄。在这种情况下,使用pi结构体。</strong></li>
</ul>
<p>这里运行会打开计算机,当时主进程会直接结束,计算器仍保留。</p>
<blockquote>
<p>疑问:这里主进程是等待子进程结束才会结束,而这个子进程是计算器本身这个进程,还是只开启计算器的进程?</p>
<p>个人理解是:IpCommandLine是传递命令参数,可能我们自己开启的进程的任务只是开启进程而不是计算器运行本身这个进程。</p>
</blockquote>
<h2 id="创建线程">创建线程</h2>
<p>定义线程结构体和启动线程两部分最重要。</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line">HANDLE hTread = (HANDLE)_beginthreadex(<span class="literal">NULL</span>, <span class="number">0</span>, create_thread_task1, <span class="literal">NULL</span>, <span class="number">0</span>, <span class="literal">NULL</span>);</span><br></pre></td></tr></table></figure>
<p>线程使用的是<code><process.h></code>头文件。</p>
<p>第三个参数是传递线程执行函数的函数指针。</p>
<p>示例代码:</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="type">unsigned</span> <span class="type">int</span> WINAPI <span class="title">create_thread_task1</span><span class="params">(LPVOID paramter)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">while</span> (<span class="number">1</span>) {</span><br><span class="line"> cout << <span class="string">"child thread running ..."</span> << endl;</span><br><span class="line"> <span class="built_in">Sleep</span>(<span class="number">500</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">create_thread_example_run</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">// 句柄声明定义</span></span><br><span class="line"> <span class="comment">// _beginthreadex()函数创建一个新的线程 指定子线程执行函数指针(函数类型固定) 返回线程的句柄</span></span><br><span class="line"> HANDLE hTread = (HANDLE)_beginthreadex(<span class="literal">NULL</span>, <span class="number">0</span>, create_thread_task1, <span class="literal">NULL</span>, <span class="number">0</span>, <span class="literal">NULL</span>);</span><br><span class="line"> <span class="keyword">while</span> (<span class="number">1</span>) {</span><br><span class="line"> cout << <span class="string">"main thread running ..."</span> << endl;</span><br><span class="line"> <span class="built_in">Sleep</span>(<span class="number">500</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 句柄可以访问线程中各种系统资源 标识对象 访问对象 资源管理</span></span><br><span class="line"> <span class="comment">// 通过CloseHandle函数关闭线程句柄 释放资源</span></span><br><span class="line"> <span class="built_in">CloseHandle</span>(hTread);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>这里线程执行的函数是固定的定义方式:</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="type">unsigned</span> <span class="type">int</span> WINAPI <span class="title">xxx</span><span class="params">(LPVOID paramter)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> ....</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<ul>
<li><code>LPVOID paramter</code>:可以接收参数,通过创建线程执行语句的第4个参数</li>
</ul>
<blockquote>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line">>参数<span class="number">1</span>:指定线程安全特性 null 表示使用默认的安全特性</span><br><span class="line">>参数<span class="number">2</span>:指定线程的堆栈大小 通常设置为<span class="number">0</span> 表示使用默认堆栈大小</span><br><span class="line">>参数<span class="number">3</span>:指向线程函数的指针</span><br><span class="line">>参数<span class="number">4</span>:传递给线程函数的参数 可以是任意类型的指针 接收是 <span class="type">void</span>* 类型</span><br><span class="line">>参数<span class="number">5</span>:指定线程初始化标志 通常设置为<span class="number">0</span></span><br><span class="line">>参数<span class="number">6</span>:用于接收新线程的标识符</span><br></pre></td></tr></table></figure>
</blockquote>
<h2 id="线程其他相关命令">线程其他相关命令</h2>
<ul>
<li>主线程等待子线程结束语句</li>
</ul>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="built_in">WaitForSingleObject</span>(hThread, INFINITE);</span><br></pre></td></tr></table></figure>
<ul>
<li>获取当前线程的ID</li>
</ul>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="built_in">GetCurrentThreadId</span>()</span><br></pre></td></tr></table></figure>
<ul>
<li>对于多个线程的处理,需要依次关闭线程,示例代码如下</li>
</ul>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">create_multi_thread</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> HANDLE handles[<span class="number">10</span>];</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < <span class="number">10</span>; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="comment">// 依次开启多个线程</span></span><br><span class="line"> handles[i] = (HANDLE)_beginthreadex(<span class="literal">NULL</span>, <span class="number">0</span>, thread_task3, <span class="literal">NULL</span>, <span class="number">0</span>, <span class="literal">NULL</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">WaitForMultipleObjects</span>(<span class="number">10</span>, handles, TRUE, INFINITE);</span><br><span class="line"> cout << <span class="string">"main thread ending ..."</span> << endl;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < <span class="number">10</span>; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="comment">// 依次关闭多个线程</span></span><br><span class="line"> <span class="built_in">CloseHandle</span>(handles[i]);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<ul>
<li>主线程等待所有子线程结束</li>
</ul>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="built_in">WaitForMultipleObjects</span>(<span class="number">3</span>, handles, TRUE, INFINITE);</span><br></pre></td></tr></table></figure>
<h2 id="补充知识">补充知识</h2>
<p>函数指针和函数指针数组,示例如下:</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">thread_task21</span><span class="params">()</span></span>{}</span><br><span class="line"></span><br><span class="line"># 函数指针数组</span><br><span class="line"><span class="built_in">void</span> (*tasks[<span class="number">3</span>])() = { thread_task1, thread_task2, thread_task3 };</span><br><span class="line"></span><br><span class="line"># 使用</span><br><span class="line">tasks[i]();</span><br></pre></td></tr></table></figure>
]]></content>
<categories>
<category>C/C++</category>
</categories>
<tags>
<tag>C</tag>
<tag>C++</tag>
<tag>多线程</tag>
</tags>
</entry>
<entry>
<title>C语言多线程编程 (二)</title>
<url>/2023/11/28/C%E8%AF%AD%E8%A8%80%E5%A4%9A%E7%BA%BF%E7%A8%8B-2/</url>
<content><![CDATA[<p>C语言实现线程的之间的同步和互斥,通过临界区、互斥量、事件、信号量实现线程的同步互斥,同时讲解一下进程之间的同步互斥。</p>
<span id="more"></span>
<h1>临界区实现同步互斥</h1>
<ol>
<li>
<p>首先我们要声明一个临界区的变量,利用临界区变量来实现临界区。</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line">CRITICAL_SECTION global_cirtical_sectioin;</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>使用临界区变量需要先初始临界区变量。</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="built_in">InitializeCriticalSection</span>(&global_cirtical_sectioin);</span><br></pre></td></tr></table></figure>
</li>
<li>
<p><strong>进入临界区,利用临界区变量上锁。</strong></p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="built_in">EnterCriticalSection</span>(&global_cirtical_sectioin);</span><br></pre></td></tr></table></figure>
</li>
<li>
<p><strong>出临界区,解锁。</strong></p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="built_in">LeaveCriticalSection</span>(&global_cirtical_sectioin);</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>使用结束后,删除临界变量。</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="built_in">DeleteCriticalSection</span>(&global_cirtical_sectioin);</span><br></pre></td></tr></table></figure>
</li>
</ol>
<p>完成的使用流程:</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line">CRITICAL_SECTION global_cirtical_sectioin;</span><br><span class="line"><span class="function"><span class="type">unsigned</span> <span class="type">int</span> WINAPI <span class="title">thread_task</span><span class="params">(LPVOID paramter)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">// 进入临界区</span></span><br><span class="line"> <span class="built_in">EnterCriticalSection</span>(&global_thread_parameter);</span><br><span class="line"> <span class="comment">// 临界区代码</span></span><br><span class="line"> ...</span><br><span class="line"> <span class="comment">// 出临界区 </span></span><br><span class="line"> <span class="built_in">LeaveCriticalSection</span>(&global_thread_parameter);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">critical_zone_synchronization</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> HANDLE hThread[<span class="number">5</span>];</span><br><span class="line"> <span class="comment">// 初始化临界区变量</span></span><br><span class="line"> <span class="built_in">InitializeCriticalSection</span>(&global_thread_code);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < <span class="number">5</span>; i++) {</span><br><span class="line"> hThread[i] = (HANDLE)_beginthreadex(<span class="literal">NULL</span>, <span class="number">0</span>, thread_task, <span class="literal">NULL</span>, <span class="number">0</span>, <span class="literal">NULL</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">WaitForMultipleObjects</span>(<span class="number">5</span>, hThread, TRUE, INFINITE);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < <span class="number">5</span>; i++) {</span><br><span class="line"> <span class="built_in">CloseHandle</span>(hThread[i]);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">DeleteCriticalSection</span>(&global_thread_code);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>这里的临界区的设置,只允许同一时间只有一个线程能够执行临界区代码。</p>
<h1>互斥量实现同步互斥</h1>
<p>大致步骤和临界区相同。</p>
<ol>
<li>
<p>初始化互斥量。</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line">HANDLE mutex = <span class="built_in">CreateMutex</span>(<span class="literal">NULL</span>, FALSE, <span class="literal">NULL</span>);</span><br></pre></td></tr></table></figure>
<p><code>CreateMutex</code>的作用是找出当前系统是否存在指定进程的示例,如果没有则创建一个互斥体。</p>
<ul>
<li>互斥对象是系统内核维护的一种数据结构,保证对象对单个线程的访问权。</li>
<li>互斥对象结构包括:使用数量(多少个线程调用该对象),线程ID(互斥对象的维护线程ID),计数器(当前线程调用该对象的次数)。</li>
<li>参数说明:</li>
</ul>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="built_in">CreateMutexA</span>(</span><br><span class="line"> _In_opt_ LPSECURITY_ATTRIBUTES lpMutexAttributes, <span class="comment">// 指向安全属性的指针</span></span><br><span class="line"> _In_ BOOL bInitialOwner, <span class="comment">// 初始化互斥对象的所有者 如果为 TRUE 表示互斥量为创建线程所有</span></span><br><span class="line"> _In_opt_ LPCSTR lpName <span class="comment">// 指向互斥对象名的指针</span></span><br><span class="line"> );</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>等待互斥量被触发。</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="built_in">WaitForSingleObject</span>(mutex, INFINITE);</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>触发互斥量。</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="built_in">ReleaseMutex</span>(mutex);</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>撤销互斥量。</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="built_in">CloseHandle</span>(mutex);</span><br></pre></td></tr></table></figure>
</li>
</ol>
<h1>事件实现同步互斥</h1>
<ol>
<li>
<p>初始化事件</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line">HANDLE event = <span class="built_in">CreateEvent</span>(<span class="literal">NULL</span>, <span class="literal">false</span>, <span class="literal">false</span>, <span class="literal">NULL</span>);</span><br></pre></td></tr></table></figure>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="function">HANDLE <span class="title">CreateEvent</span><span class="params">(</span></span></span><br><span class="line"><span class="params"><span class="function"> LPSECURITY_ATTRIBUTES lpEventAttributes, <span class="comment">// 安全属性结构体指针</span></span></span></span><br><span class="line"><span class="params"><span class="function"> BOOL bManualReset, <span class="comment">// 是否手动复位</span></span></span></span><br><span class="line"><span class="params"><span class="function"> BOOL bInitialState, <span class="comment">// 初始状态</span></span></span></span><br><span class="line"><span class="params"><span class="function"> LPCTSTR lpName <span class="comment">// 事件名称</span></span></span></span><br><span class="line"><span class="params"><span class="function">)</span></span>;</span><br></pre></td></tr></table></figure>
<ul>
<li><code>lpEventAttributes</code>:一个指向SECURITY_ATTRIBUTES结构体的指针,用于设置事件对象的安全属性。如果该参数为NULL,则事件对象会继承调用进程的安全属性。</li>
<li><code>bManualReset</code>:一个布尔值,用于指定事件对象的类型。如果该参数为TRUE,则表示创建的是手动复位事件对象;如果该参数为FALSE,则表示创建的是自动复位事件对象。手动复位事件对象必须通过调用<code>ResetEvent</code>函数来将事件状态复位(即重置为未激发状态);而自动复位事件对象则会在有信号触发时自动将其状态复位。</li>
<li><code>bInitialState</code>:一个布尔值,用于指定事件对象的初始状态。如果该参数为TRUE,则表示在创建事件对象时立即将其设置为已激发状态(signaled);如果该参数为FALSE,则表示事件对象初始状态为未激发状态(nonsignaled)。</li>
<li><code>lpName</code>:一个字符串指针,用于指定事件对象的名称。如果该参数为NULL,则表示创建一个无名事件对象;否则表示创建命名的事件对象。需要注意的是,如果同时存在同名的命名事件对象,则会返回该事件对象的句柄。</li>
</ul>
</li>
<li>
<p>等待事件发生</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="built_in">WaitForSingleObject</span>(event, INFINITE);</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>触发事件</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="built_in">SetEvent</span>(event);</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>撤销事件</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="built_in">CloseHandle</span>(event);</span><br></pre></td></tr></table></figure>
</li>
</ol>
<h1>信号量同步</h1>
<ol>
<li>
<p>初始化信号量</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 当前0个资源、最大允许1个同时访问</span></span><br><span class="line">HANDLE semaphore = <span class="built_in">CreateSemaphore</span>(<span class="literal">NULL</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="literal">NULL</span>);</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>等待$信号量>1$</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="built_in">WaitForSingleObject</span>(semaphore, INFINITE);</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>释放一个资源,信号量加1</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="built_in">ReleaseSemaphore</span>(semaphore, <span class="number">1</span>, <span class="literal">NULL</span>);</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>撤销信号量</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="built_in">CloseHandle</span>(semaphore);</span><br></pre></td></tr></table></figure>
</li>
</ol>
<h1>进程之间互斥信号量实现互斥</h1>
<p>和线程之间原理一样,这里多了一步需要打开互斥对象,互斥对象有操作内核管理,通过名称查找到。</p>
<p>互斥对象存在时,同名的进程时不能运行的。</p>
<ol>
<li>
<p>创建互斥量</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line">HANDLE hMutex = <span class="built_in">CreateMutex</span>(<span class="literal">NULL</span>, TRUE, MUTEX_NAME);</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>打开互斥量</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line">HANDLE hMutex = <span class="built_in">OpenMutex</span>(MUTEX_ALL_ACCESS, TRUE, MUTEX_NAME);</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>触发互斥量</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="built_in">ReleaseMutex</span>(hMutex);</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>等待互斥量触发</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="built_in">WaitForSingleObject</span>(hMutex, <span class="number">10000</span>);</span><br></pre></td></tr></table></figure>
</li>
</ol>
<h1>存在问题</h1>
<h2 id="WaitForSingleObject">WaitForSingleObject()</h2>
<p><code>WaitForSingleObject</code>函数的执行流程如下:</p>
<ol>
<li>线程调用<code>WaitForSingleObject</code>函数并传入需要等待的对象的句柄以及等待时间的长度。</li>
<li>系统检查对象的当前状态:
<ul>
<li>如果对象已经是 signaled 状态(已激发),则直接返回<code>WAIT_OBJECT_0</code>,线程可以继续执行后续操作。</li>
<li>如果对象不是 signaled 状态(未激发),则线程进入等待状态,并将该线程从可执行状态转换为等待状态,直到以下三种情况之一发生:
<ul>
<li>对象被激发,即对象状态变为 signaled。此时,线程会被唤醒,并返回<code>WAIT_OBJECT_0</code>,线程可以继续执行后续操作。</li>
<li>等待超时,即指定的等待时间到达。此时,线程会被唤醒,并返回<code>WAIT_TIMEOUT</code>,线程可以根据需要进行相应处理。</li>
<li>等待的对象被放弃。这通常出现在使用互斥体时,当互斥体的所有者线程意外终止而没有正确释放互斥体时,其他线程在等待该互斥体时会返回<code>WAIT_ABANDONED</code>。</li>
</ul>
</li>
</ul>
</li>
<li>线程根据返回值进行相应的处理。</li>
</ol>
<h2 id="不同线程之间临界区和互斥量不起作用">不同线程之间临界区和互斥量不起作用</h2>
]]></content>
<categories>
<category>C/C++</category>
</categories>
<tags>
<tag>C</tag>
<tag>C++</tag>
<tag>多线程</tag>
<tag>同步互斥</tag>
</tags>
</entry>
<entry>
<title>MySQL常用语法</title>
<url>/2023/12/03/MySQL%E5%B8%B8%E7%94%A8%E8%AF%AD%E6%B3%95/</url>
<content><![CDATA[<p>MySQL增删改查,多表查询,视图,存储过程,存储函数,游标。</p>
<span id="more"></span>
<h1>DDL</h1>
<h2 id="表操作-修改">表操作-修改</h2>
<p>添加字段</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">alter table 表名 add 字段名 类型(长度) [约束];</span><br></pre></td></tr></table></figure>
<p>修改数据类型</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">alter table 表名 modify 字段名 新数据类型(长度);</span><br></pre></td></tr></table></figure>
<p>修改字段名和字段类型</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">alter table 表名 change 旧字段名 新字段名 类型(长度) [约束];</span><br></pre></td></tr></table></figure>
<p>删除字段</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">alter table 表名 drop 字段名;</span><br></pre></td></tr></table></figure>
<p>修改表名</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">alter table 表名 rename to 新表名;</span><br></pre></td></tr></table></figure>
<h2 id="约束">约束</h2>
<h2 id="外键">外键</h2>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">constraint 外键名称 foreign key 外键字段名 references 主表(列名)</span><br></pre></td></tr></table></figure>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">alter table 表名 add constraint 外键名称 foreign key (外键字段名) references 主表 (主表列名);</span><br></pre></td></tr></table></figure>
<h1>索引</h1>
<ol>
<li>
<p>创建索引</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">create index index_name on table_name (index_col_name, ...);</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>查看索引</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">show index from table_name;</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>删除索引</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">drop index index_name on table_name;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<h1>视图</h1>
<ol>
<li>
<p>创建视图</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">create view view_name as select语句</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>查询</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line"># 查看视图语句</span><br><span class="line">show create view view_name;</span><br><span class="line"># 查看视图数据</span><br><span class="line">select * from view_name ...;</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>修改</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">create [or replace] view view_name as select语句;</span><br><span class="line">alter view view_name as select语句;</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>删除</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">drop view [if exists] view_name ...;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<h1>存储过程</h1>
<ol>
<li>
<p>创建</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">create procedure 存储过程名称([[in or out]参数列表])</span><br><span class="line">begin</span><br><span class="line"> -- SQL语句</span><br><span class="line">end;</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>调用</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">call 名称 ([参数]);</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>删除</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">drop procedure [if exists] procedure_name ...;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<h2 id="参数">参数</h2>
<table>
<thead>
<tr>
<th>类型</th>
<th>含义</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<tr>
<td>IN</td>
<td>作为输入</td>
<td>默认</td>
</tr>
<tr>
<td>OUT</td>
<td>作为输出,返回值</td>
<td></td>
</tr>
<tr>
<td>INOUT</td>
<td>即可作为输入参数也可作为输出参数</td>
<td></td>
</tr>
</tbody>
</table>
<h2 id="变量">变量</h2>
<ol>
<li>
<p>查看系统变量</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">SHOW [ SESSION | GLOBAL ] VARIABLES ; -- 查看所有系统变量</span><br><span class="line">SHOW [ SESSION | GLOBAL ] VARIABLES LIKE '......'; -- 可以通过LIKE模糊匹配方式查找变量</span><br><span class="line">SELECT @@[SESSION | GLOBAL] 系统变量名; -- 查看指定变量的值</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>设置系统变量</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">SET [ SESSION | GLOBAL ] 系统变量名 = 值 ;</span><br><span class="line">SET @@[SESSION | GLOBAL] 系统变量名 = 值 ;</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>用户自定义变量赋值</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">SET @var_name = expr [, @var_name = expr] ... ;</span><br><span class="line">SET @var_name := expr [, @var_name := expr] ... ;</span><br><span class="line"></span><br><span class="line">SELECT @var_name := expr [, @var_name := expr] ... ;</span><br><span class="line">SELECT 字段名 INTO @var_name FROM 表名;</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>自定义变量使用</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">SELECT @var_name</span><br></pre></td></tr></table></figure>
</li>
</ol>
<p>局部变量</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line"># 声明</span><br><span class="line">declare 变量名 变量类型 [default ...];</span><br><span class="line"></span><br><span class="line"># 赋值</span><br><span class="line">set 变量名 = 值;</span><br><span class="line">set 变量名 := 值;</span><br><span class="line">select 字段名 into 变量名 from 表名 ...;</span><br></pre></td></tr></table></figure>
<h2 id="条件-循环语句">条件/循环语句</h2>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">if 条件 then</span><br><span class="line"> ...</span><br><span class="line">elseif 条件2 then</span><br><span class="line"> ...</span><br><span class="line">else</span><br><span class="line"> ...</span><br><span class="line">end if;</span><br></pre></td></tr></table></figure>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">while 条件 do</span><br><span class="line"> -- SQL逻辑</span><br><span class="line">end while;</span><br></pre></td></tr></table></figure>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">-- 先执行一次逻辑,然后判定UNTIL条件是否满足,如果满足,则退出。如果不满足,则继续下一次循环</span><br><span class="line">REPEAT</span><br><span class="line"> SQL逻辑...;</span><br><span class="line"> UNTIL 条件</span><br><span class="line">END REPEAT;</span><br></pre></td></tr></table></figure>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">[begin_label:] LOOP</span><br><span class="line"> SQL逻辑...</span><br><span class="line">END LOOP [end_label];</span><br><span class="line"></span><br><span class="line">LEAVE label; -- 退出指定标记的循环体</span><br><span class="line">ITERATE label; -- 直接进入下一次循环</span><br></pre></td></tr></table></figure>
<h1>游标</h1>
<ol>
<li>
<p>声明游标</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">declare 游标名称 cursor for 查询语句;</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>打开游标</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">open 游标名称;</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>获取游标</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">fetch 游标 into 变量 [, 变量 ...];</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>关闭游标</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">close 游标名称;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<p>示例</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">create procedure p8()</span><br><span class="line">begin</span><br><span class="line"> declare t_index char(6);</span><br><span class="line"> declare price float;</span><br><span class="line"> declare flag bool default true;</span><br><span class="line"> declare cur_update cursor for</span><br><span class="line"> (select goods.goodsno, goods.saleprice from goods join category c on c.categoryno = goods.categoryno where c.categoryno = 'cn001');</span><br><span class="line"> declare continue handler for not found set flag := false;</span><br><span class="line"></span><br><span class="line"> open cur_update;</span><br><span class="line"> while flag do</span><br><span class="line"> fetch cur_update into t_index, price;</span><br><span class="line"> update goods set saleprice = price * 0.9 where goodsno = t_index;</span><br><span class="line"> end while;</span><br><span class="line"> close cur_update;</span><br><span class="line">end;</span><br></pre></td></tr></table></figure>
<p>MySQL游标的关闭是通过处理异常来关闭的。</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">declare continue handler for not found set flag := false;</span><br></pre></td></tr></table></figure>
<h1>触发器</h1>
<p>触发器是与表相关的数据库对象,指在<code>insert/update/delete</code>之前<code>before</code>或之后<code>after</code>,触发并执行触发器中定义的SQL语句。</p>
<table>
<thead>
<tr>
<th>触发器类型</th>
<th>NEW 和 OLD</th>
</tr>
</thead>
<tbody>
<tr>
<td>INSERT</td>
<td>NEW 表示将要或者已经新增的数据</td>
</tr>
<tr>
<td>UPDATE</td>
<td>OLD 表示修改之前的数据,NEW表示将要或已经修改后的数据</td>
</tr>
<tr>
<td>DELETE</td>
<td>OLD 表示将要或者已经删除的数据</td>
</tr>
</tbody>
</table>
<ol>
<li>
<p>创建</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">create trigger trigger_name</span><br><span class="line">before/after insert/update/delete</span><br><span class="line">on tb1_name for each row -- 行级触发器</span><br><span class="line">begin</span><br><span class="line"> -- SQL执行</span><br><span class="line">end;</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>查看</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">show triggers;</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>删除</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">drop trigger trigger_name;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<p>示例</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">create trigger supplier_delete_trigger</span><br><span class="line"> before delete on supplier for each row</span><br><span class="line">begin</span><br><span class="line"> delete from salebill where salebill.goodsno in</span><br><span class="line"> (select g.goodsno from goods g join supplier s on g.supplierno = s.supplierno where s.supplierno = OLD.supplierno);</span><br><span class="line"> delete from goods where goods.supplierno = OLD.supplierno;</span><br><span class="line">end;</span><br></pre></td></tr></table></figure>
]]></content>
<categories>
<category>数据库</category>
</categories>
<tags>
<tag>MySQL</tag>
<tag>MySQL常用命令</tag>
</tags>
</entry>
<entry>
<title>Elaticsearch</title>
<url>/2023/12/08/Elaticsearch/</url>
<content><![CDATA[<p>讲述elasticsearch的基本用法,包括创建库、建立倒排索引、排序规则、拼音搜索、地理位置搜索的基础实现。</p>
<span id="more"></span>
<h1>初识</h1>
<p>elasticsearch主要是倒排索引,通过将整个数据差分成关键字,建立以关键字为索引的表,加快我们对内容的一个搜索。简单来说就是把一整个文本差分成关键字,然后我们搜索关键字,找到这一文本。</p>
<p>这里只简单介绍一些常用的语法,具体可以参考官方文档[Quick start | Elasticsearch Guide <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/getting-started.html">8.11] | Elastic</a></p>
<p>在使用elasticsearch之前需要先安装下载,如下。</p>
<h2 id="Elasticsearch安装">Elasticsearch安装</h2>
<p>这里使用docker来安装下载elasticsearch,关于docker的使用,可以参考其他docker命令教程,这里不在赘述。</p>
<ol>
<li>
<p>首先在docker上面创建网络。</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">docker network create es-net</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>拉取elasticsearch镜像。</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">docker pull elasticsearch:8.11.1</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>创建挂载点目录,并修改目录权限</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> -p /usr/local/es/data /usr/local/es/config /usr/local/es/plugins</span><br><span class="line"></span><br><span class="line"><span class="built_in">chmod</span> 777 /usr/local/es/data</span><br><span class="line"><span class="built_in">chmod</span> 777 /usr/local/es/config</span><br><span class="line"><span class="built_in">chmod</span> 777 /usr/local/es/plugins</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>部署单点es,创建es容器。</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">docker run -d \</span><br><span class="line"> --restart=always \</span><br><span class="line"> --name es \</span><br><span class="line"> --network es-net \</span><br><span class="line"> -p 9200:9200 \</span><br><span class="line"> -p 9300:9300 \</span><br><span class="line"> --privileged \</span><br><span class="line"> -v /usr/local/es/data:/usr/share/elasticsearch/data \</span><br><span class="line"> -v /usr/local/es/plugins:/usr/share/elasticsearch/plugins \</span><br><span class="line"> -e <span class="string">"discovery.type=single-node"</span> \</span><br><span class="line"> -e <span class="string">"ES_JAVA_OPTS=-Xms512m -Xmx512m"</span> \</span><br><span class="line">elasticsearch:8.11.1</span><br></pre></td></tr></table></figure>
<p>命令解释:</p>
<ul>
<li>
<p><code>--name es</code>:设置集群名称</p>
</li>
<li>
<p><code>-e "ES_JAVA_OPTS=-Xms512m -Xmx512m"</code>:内存大小</p>
</li>
<li>
<p><code>-e "discovery.type=single-node"</code>:非集群模式</p>
</li>
<li>
<p><code>-v /usr/local/es/data:/usr/share/elasticsearch/data</code>:挂载逻辑卷,绑定es的数据目录</p>
</li>
<li>
<p><code>-v /usr/local/es/plugins:/usr/share/elasticsearch/plugins</code>:挂载逻辑卷,绑定es的插件目录</p>
</li>
<li>
<p><code>--privileged</code>:授予逻辑卷访问权</p>
</li>
<li>
<p><code>--network es-net</code> :加入一个名为es-net的网络中</p>
</li>
<li>
<p><code>-p 9200:9200</code>:端口映射配置</p>
</li>
</ul>
</li>
<li>
<p>修改elasticsearch配置文件,将远程连接验证关闭掉。</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">docker <span class="built_in">exec</span> -it es /bin/bash</span><br><span class="line"><span class="built_in">cd</span> config</span><br><span class="line"><span class="built_in">echo</span> <span class="string">'xpack.security.enabled: false'</span> >> elasticsearch.yml</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>重启服务,访问elasticsearch的端口地址,结果如下,则启动成功。</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">docker restart es</span><br></pre></td></tr></table></figure>
<p><img src="/2023/12/08/Elaticsearch/image-20231209114652606.png" alt="image-20231209114652606"></p>
</li>
</ol>
<h2 id="kibana安装">kibana安装</h2>
<p>图形化使用Elasticsearch。</p>
<ol>
<li>
<p>拉取Kibana镜像。</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">docker pull kibana:8.11.1</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>部署Kinana,创建Kinana容器。</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">docker run -d \</span><br><span class="line"> --restart=always \</span><br><span class="line"> --name kibana \</span><br><span class="line"> --network es-net \</span><br><span class="line"> -p 5601:5601 \</span><br><span class="line"> -e ELASTICSEARCH_HOSTS=http://es:9200 \</span><br><span class="line">kibana:8.11.1</span><br></pre></td></tr></table></figure>
<p>命令解释:</p>
<ul>
<li><code>--network es-net</code> :加入一个名为es-net的网络中,与elasticsearch在同一个网络中</li>
<li><code>-e ELASTICSEARCH_HOSTS=http://es:9200"</code>:设置elasticsearch的地址,因为kibana已经与elasticsearch在一个网络,因此可以用容器名直接访问elasticsearch</li>
<li><code>-p 5601:5601</code>:端口映射配置</li>
</ul>
</li>
</ol>
<h2 id="安装IK分词器">安装IK分词器</h2>
<p>IK分词是支持中文分词的插件。</p>
<ol>
<li>
<p>进入容器内部。</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">docker <span class="built_in">exec</span> -it es /bin/bash</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>在线安装IK分词器。</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v8.11.1/elasticsearch-analysis-ik-8.11.1.zip</span><br></pre></td></tr></table></figure>
</li>
</ol>
<h1>索引库操作</h1>
<p>索引库操作相对对数据库的表的操作,存储数据之前要先创建库和表。</p>
<h2 id="Mapping映射属性">Mapping映射属性</h2>
<p>Mapping对索引库的文档约束。</p>
<p>常见属性:</p>
<ul>
<li>
<p>type:字段的数据类型,常见的有:</p>
<ul>
<li>字符串:text(可分词的文本),keyword(精确值)</li>
<li>数值:long、integer、short、byte、double、float</li>
<li>布尔:boolean</li>
<li>日期:date</li>
<li>对象:object</li>
</ul>
<p>对于数组只看器元素是什么类型。</p>
</li>
<li>
<p>index:指定字段是否创建索引。<code>index=true 表示字段创建索引</code></p>
</li>
<li>
<p>analyzer:指定使用那种分词器,针对text可分词文本使用</p>
</li>
<li>
<p>properties:该字段的字段(对象类型)</p>
</li>
</ul>
<h2 id="创建索引库">创建索引库</h2>
<p>相对于建立一张表,对字段进行类型定义,是否创建索引,指定使用分词器类型等操作,示例:</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">PUT /索引库名称</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"mappings"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"properties"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"字段名"</span><span class="punctuation">:</span><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"type"</span><span class="punctuation">:</span> <span class="string">"text"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"analyzer"</span><span class="punctuation">:</span> <span class="string">"ik_smart"</span></span><br><span class="line"> <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"字段名2"</span><span class="punctuation">:</span><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"type"</span><span class="punctuation">:</span> <span class="string">"keyword"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"index"</span><span class="punctuation">:</span> <span class="string">"false"</span></span><br><span class="line"> <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"字段名3"</span><span class="punctuation">:</span><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"properties"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"子字段"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"type"</span><span class="punctuation">:</span> <span class="string">"keyword"</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line"> <span class="comment">// ...略</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
<p>在<code>properties</code>属性中定义字段,字段中定义数据类型,是否建立索引,采用什么分词器。</p>
<p>如果中还有其他字段,该字段也能够定义<code>properties</code>属性。</p>
<p>实际搜索,我们可能是对多个字段内容进行搜索,为了加快搜索效率,我们可以将参与搜索的字段整合在一起。</p>
<p>示例:</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">PUT /索引库名称</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"mappings"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"properties"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"字段名"</span><span class="punctuation">:</span><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"type"</span><span class="punctuation">:</span> <span class="string">"text"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"analyzer"</span><span class="punctuation">:</span> <span class="string">"ik_max_word"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"copy_to"</span><span class="punctuation">:</span> <span class="string">"all"</span></span><br><span class="line"> <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"字段名2"</span><span class="punctuation">:</span><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"type"</span><span class="punctuation">:</span> <span class="string">"text"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"analyzer"</span><span class="punctuation">:</span> <span class="string">"ik_max_word"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"copy_to"</span><span class="punctuation">:</span> <span class="string">"all"</span></span><br><span class="line"> <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"all"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"type"</span><span class="punctuation">:</span> <span class="string">"text"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"analyzer"</span><span class="punctuation">:</span> <span class="string">"ik_max_word"</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="comment">// ...略</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
<p>我们再定义一个字段<code>all</code>,将参与搜索的字段都加上<code>"copy_to": "all"</code>,相当于绑定到<code>all</code>这个字段上,最后我们只需要对<code>all</code>这个字段进行全文搜索,就可以实现对多个字段进行搜索。<code>all</code>字段也要指定分词器。</p>
<h2 id="查询索引库">查询索引库</h2>
<p>语法如下:</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">GET /索引库名</span><br></pre></td></tr></table></figure>
<h2 id="修改索引库">修改索引库</h2>
<p>索引库核心就是索引的数据结构,一旦改变就需要重新创建倒排索引。索引库<strong>一旦创建就无法修改mapping</strong>。</p>
<p>虽然无法修改mapping中已有的字段,但允许添加新字段到mapping中,不会对倒排索引产生影响。</p>
<p>添加字段语法如下:</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">PUT /索引库名/_mapping</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"properties"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"新字段名"</span><span class="punctuation">:</span><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"type"</span><span class="punctuation">:</span> <span class="string">"integer"</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
<p>和创建的请求方式不同,数据定义的方式是相同的。</p>
<h2 id="删除索引库">删除索引库</h2>
<p>语法如下:</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">DELETE /索引库名</span><br></pre></td></tr></table></figure>
<h1>文档操作</h1>
<h2 id="新增文档">新增文档</h2>
<p>数据库中<code>insert</code>语句,来添加数据。语法如下:</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">POST /索引库名/_doc/文档id</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"字段1"</span><span class="punctuation">:</span> <span class="string">"值1"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"字段2"</span><span class="punctuation">:</span> <span class="string">"值2"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"字段3"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"子属性1"</span><span class="punctuation">:</span> <span class="string">"值3"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"子属性2"</span><span class="punctuation">:</span> <span class="string">"值4"</span></span><br><span class="line"> <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
<h2 id="查询文档">查询文档</h2>
<p>这里简单介绍查询,查询作为索引库的主要功能在DSL重点讲解。</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">GET /<span class="punctuation">{</span>索引库名称<span class="punctuation">}</span>/_doc/<span class="punctuation">{</span>id<span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
<h2 id="删除文档">删除文档</h2>
<p>语法:</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">DELETE /<span class="punctuation">{</span>索引库名<span class="punctuation">}</span>/_doc/id值</span><br></pre></td></tr></table></figure>
<h2 id="修改文档">修改文档</h2>
<p>修改文档有两种方式:</p>
<ol>
<li>全量修改:直接覆盖原来的文档</li>
<li>增量修改:修改文档的部分字段</li>
</ol>
<h3 id="全量修改">全量修改</h3>
<p>全量修改的本质是删除指定id的文档,新增一个相同的id的文档。</p>
<p>如果根据id删除时,id不存在,直接执行新增。</p>
<p>语法:</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">PUT /<span class="punctuation">{</span>索引库名<span class="punctuation">}</span>/_doc/文档id</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"字段1"</span><span class="punctuation">:</span> <span class="string">"值1"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"字段2"</span><span class="punctuation">:</span> <span class="string">"值2"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="comment">// ... 略</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
<p>语法和新增文档的语法一样。</p>
<h3 id="增量修改">增量修改</h3>
<p>增量修改只修改指定id匹配的文档中部分字段。</p>
<p>语法如下:</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">POST /<span class="punctuation">{</span>索引库名<span class="punctuation">}</span>/_update/文档id</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"doc"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"字段名"</span><span class="punctuation">:</span> <span class="string">"新的值"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
<h1>DSL查询文档</h1>
<p>DSL查询分类:</p>
<ul>
<li>查询所有:<code>match_all</code></li>
<li>全文检索:利用分词器对用户输入的内容进行分词,然后去倒排索引库中匹配。</li>
<li>精确查询:根据精确词条值查找数据。</li>
<li>地理查询:根据经纬度查询。</li>
<li>复合查询:将上述各种查询条件组合起来,合并查询条件。</li>
</ul>
<p>查询语句基本一致:</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">GET /indexName/_search</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"query"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"查询类型"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"查询条件"</span><span class="punctuation">:</span> <span class="string">"条件值"</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
<h2 id="全文检索">全文检索</h2>
<p>全文检索基本流程:</p>
<ul>
<li>对用户搜索内容进行分词,等到搜索词条</li>
<li>根据词条去倒排索引库中匹配,得到文档id</li>
<li>根据文档id找到文档,返回给用户</li>
</ul>
<h3 id="基本语法">基本语法</h3>
<ul>
<li>match查询:单个字段查询</li>
<li>multi_match查询:多字段查询,任意一个字段符合要求就算符合查询条件</li>
</ul>
<p>match查询语法</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">GET /indexName/_search</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"query"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"match"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"FIELD"</span><span class="punctuation">:</span> <span class="string">"TEXT"</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
<p>multi_match查询语法</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">GET /indexName/_search</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"query"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"multi_match"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"query"</span><span class="punctuation">:</span> <span class="string">"TEXT"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"fields"</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">"FIELD1"</span><span class="punctuation">,</span> <span class="string">" FIELD12"</span><span class="punctuation">]</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
<h2 id="精确查询">精确查询</h2>
<p>精确查询一般是查找keyword,数值,日期,boolean类型字段。不会对搜索条件分词。</p>
<h3 id="基本语法-2">基本语法</h3>
<p>两种实现方式:</p>
<ul>
<li>
<p>term查询</p>
<p>精确查询的字段是不分词的字段,因此查询的条件也必须是不分词的词条。</p>
<p>查询时,用户输入的内容和自动值完全匹配时才认为符合条件。</p>
</li>
<li>
<p>range查询</p>
<p>范围查询,一般应用在对数值类型做范围过滤。</p>
</li>
</ul>
<p>term查询语法</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">GET /indexName/_search</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"query"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"term"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"FIELD"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"value"</span><span class="punctuation">:</span> <span class="string">"VALUE"</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
<p>range查询语法</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">GET /indexName/_search</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"query"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"range"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"FIELD"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"gte"</span><span class="punctuation">:</span> <span class="number">10</span><span class="punctuation">,</span> <span class="comment">// 这里的gte代表大于等于,gt则代表大于</span></span><br><span class="line"> <span class="attr">"lte"</span><span class="punctuation">:</span> <span class="number">20</span> <span class="comment">// lte代表小于等于,lt则代表小于</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
<h2 id="地理查询">地理查询</h2>
<p>根据经纬度查询,官方文档[Geo queries | Elasticsearch Guide <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-queries.html">8.11] | Elastic</a></p>
<h3 id="矩阵范围查询">矩阵范围查询</h3>
<p>查询时,需要指定矩形的<strong>左上</strong>、<strong>右下</strong>两个点的坐标,然后画出一个矩形,落在该矩形内的都是符合条件的点。</p>
<p>基本语法</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">GET /indexName/_search</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"query"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"geo_bounding_box"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"FIELD"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"top_left"</span><span class="punctuation">:</span> <span class="punctuation">{</span> <span class="comment">// 左上点</span></span><br><span class="line"> <span class="attr">"lat"</span><span class="punctuation">:</span> <span class="number">31.1</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"lon"</span><span class="punctuation">:</span> <span class="number">121.5</span></span><br><span class="line"> <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"bottom_right"</span><span class="punctuation">:</span> <span class="punctuation">{</span> <span class="comment">// 右下点</span></span><br><span class="line"> <span class="attr">"lat"</span><span class="punctuation">:</span> <span class="number">30.9</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"lon"</span><span class="punctuation">:</span> <span class="number">121.7</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
<h3 id="附近查询">附近查询</h3>
<p>查询到指定中心点小于某个距离值的所有文档。</p>
<p>基本语法</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">GET /indexName/_search</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"query"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"geo_distance"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"distance"</span><span class="punctuation">:</span> <span class="string">"15km"</span><span class="punctuation">,</span> <span class="comment">// 半径</span></span><br><span class="line"> <span class="attr">"FIELD"</span><span class="punctuation">:</span> <span class="string">"31.21,121.5"</span> <span class="comment">// 圆心</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
<h2 id="复合查询">复合查询</h2>
<p>复合查询将其他简单的查询组合起来,实现更复杂的搜索逻辑。</p>
<p>常见两种:</p>
<ul>
<li>function score:算法函数查询,可以控制文档排名</li>
<li>bool query:布尔查询,利用逻辑关系组合多个其他查询,实现复杂搜索</li>
</ul>
<h3 id="相关性算分">相关性算分</h3>
<p>进行文档搜索时,文档结果会根据搜索词条的关联度打分,返回结果时按分值降序排列。</p>
<p>Elasticsearch中早期使用的打分算法是TF-IDF算法,公式如下:<br>
$$<br>
TF(词条频率)=\frac{词条出现次数}{文档中词条总数} \<br>
IDF(逆文档频率)=\log(\frac{文档总数}{包含词条的文档总数}) \<br>
socre = \sum_{i}^{n}TF(词条频率)\times IDF(逆文档频率)<br>
$$</p>
<p>在5.1版本之后,改用了BM25算法,公式如下:<br>
$$<br>
Socre(Q,d)=\sum_{i}^{n}\log(1+\frac{N-n+0.5}{n+0.5})\cdot\frac{f_i}{f_i+k_i\cdot(1-b+b\cdot\frac{dl}{avgdl}}<br>
$$</p>
<p>TF-IDF算法缺陷,词条频率越高,文档得分也会越高,单个词条对文档影响较大。而BM25则会让单个词条的算分有个上线。</p>
<p><img src="/2023/12/08/Elaticsearch/image-20231209205613877.png" alt="image-20231209205613877"></p>
<h4 id="基础语法">基础语法</h4>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">GET /your_table_name/_search</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"query"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"function_score"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"query"</span><span class="punctuation">:</span> <span class="punctuation">{</span> .... <span class="punctuation">}</span><span class="punctuation">,</span> <span class="comment">// 原始查询,可以是任意条件</span></span><br><span class="line"> <span class="attr">"functions"</span><span class="punctuation">:</span> <span class="punctuation">[</span> <span class="comment">// 算分函数</span></span><br><span class="line"> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"filter"</span><span class="punctuation">:</span> <span class="punctuation">{</span> <span class="comment">// 满足的条件,品牌必须是如家</span></span><br><span class="line"> <span class="attr">"term"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"Field"</span><span class="punctuation">:</span> <span class="string">"TEXT"</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"weight"</span><span class="punctuation">:</span> VALUE <span class="comment">// 算分权重</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"boost_mode"</span><span class="punctuation">:</span> <span class="string">"sum"</span> <span class="comment">// 加权模式,求和</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
<ul>
<li>
<p>原始查询条件:query部分,基于这个条件,并且基于BM25算法给文档打分,原始算分。</p>
</li>
<li>
<p>过滤条件:filter部分,符合该条件的文档才会重新算分。</p>
</li>
<li>
<p>算法函数:根据这个函数做运算,得到函数算分。</p>
<p>四种函数:</p>
<ul>
<li>weight:函数结果是常量</li>
<li>field_value_factor:以文档的某个字段值作为函数结果</li>
<li>random_score:以随机数作为函数结果</li>
<li>script_score:自定义算分函数算法</li>
</ul>
</li>
<li>
<p>运算模式:算分函数的结果,原始查询的相关性算分,两者之间的运算方式</p>
<p>包括:</p>
<ul>
<li>multiply:相乘</li>
<li>replace:用算分函数的score替换原来的score</li>
<li>其他:sum、avg、max、min</li>
</ul>
</li>
</ul>
<p>function_score算分流程:</p>
<ol>
<li>根据原始条件查询搜索文档,并且计算相关性算分,得到原始算分</li>
<li>根据过滤条件,过滤文档</li>
<li>符合过滤条件的文档,基于算分函数运算,得到函数算分</li>
<li>将原始算分和函数算分基于运算模式做运算,得到最终结果,作为相关性算分</li>
</ol>
<h3 id="布尔查询">布尔查询</h3>
<p>布尔查询时一个或多个查询字句的组合,每一个子句就是一个子查询。子查询的组合方式有:</p>
<ul>
<li>must:必须匹配每个子查询,类似“与”</li>
<li>should:选择性匹配子查询,类似”或“</li>
<li>must_not:必须不匹配,类似”非“</li>
<li>filter:必须匹配,不参与算法</li>
</ul>
<p>需要注意的是,参与打分的字段越多,查询的性能也越差。建议:</p>
<ul>
<li>搜索框关键字采用全文检索,使用must查询,参与算法</li>
<li>其他过滤条件,采用filter查询,不参与算分。</li>
</ul>
<h4 id="基本语法-3">基本语法</h4>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">GET /your_table_name/_search</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"query"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"bool"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"must"</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line"> <span class="punctuation">{</span><span class="attr">"term"</span><span class="punctuation">:</span> <span class="punctuation">{</span><span class="attr">"FIELD"</span><span class="punctuation">:</span> <span class="string">"TEXT"</span> <span class="punctuation">}</span><span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"should"</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line"> <span class="punctuation">{</span><span class="attr">"term"</span><span class="punctuation">:</span> <span class="punctuation">{</span><span class="attr">"FIELD"</span><span class="punctuation">:</span> <span class="string">"TEXT"</span> <span class="punctuation">}</span><span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line"> <span class="punctuation">{</span><span class="attr">"term"</span><span class="punctuation">:</span> <span class="punctuation">{</span><span class="attr">"FIELD"</span><span class="punctuation">:</span> <span class="string">"TEXT"</span> <span class="punctuation">}</span><span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"must_not"</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line"> <span class="punctuation">{</span> <span class="attr">"range"</span><span class="punctuation">:</span> <span class="punctuation">{</span> <span class="attr">"FIELD"</span><span class="punctuation">:</span> <span class="punctuation">{</span> <span class="attr">"lte"</span><span class="punctuation">:</span> <span class="number">500</span> <span class="punctuation">}</span> <span class="punctuation">}</span><span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"filter"</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line"> <span class="punctuation">{</span> <span class="attr">"range"</span><span class="punctuation">:</span> <span class="punctuation">{</span><span class="attr">"FIELD"</span><span class="punctuation">:</span> <span class="punctuation">{</span> <span class="attr">"gte"</span><span class="punctuation">:</span> <span class="number">45</span> <span class="punctuation">}</span> <span class="punctuation">}</span><span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">]</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
<h1>搜索结果处理</h1>
<h2 id="排序">排序</h2>
<p>指定排序条件,处理返回结果的顺序。</p>
<h3 id="普通字段排序">普通字段排序</h3>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">GET /indexName/_search</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"query"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"match_all"</span><span class="punctuation">:</span> <span class="punctuation">{</span><span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"sort"</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line"> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"FIELD"</span><span class="punctuation">:</span> <span class="string">"desc"</span> <span class="comment">// 排序字段、排序方式ASC、DESC</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">]</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
<p>如果有多个字段参与排序,是按照写的字段先后排序,先根据第一个字段排序,然后根据后面的字段排序。</p>
<p>这里sort是对最后结果进行排序,而之后的<code>order</code>是对相关字段进行排序。如果指定sort,原来的算法排序会被取代,这里通过将<code>_score</code>字段加上,实现原算分排序。</p>
<h3 id="地理坐标排序">地理坐标排序</h3>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">GET /indexName/_search</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"query"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"match_all"</span><span class="punctuation">:</span> <span class="punctuation">{</span><span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"sort"</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line"> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"_geo_distance"</span> <span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"FIELD"</span> <span class="punctuation">:</span> <span class="string">"纬度,经度"</span><span class="punctuation">,</span> <span class="comment">// 文档中geo_point类型的字段名、目标坐标点</span></span><br><span class="line"> <span class="attr">"order"</span> <span class="punctuation">:</span> <span class="string">"asc"</span><span class="punctuation">,</span> <span class="comment">// 排序方式</span></span><br><span class="line"> <span class="attr">"unit"</span> <span class="punctuation">:</span> <span class="string">"km"</span> <span class="comment">// 排序的距离单位</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">]</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
<p>指定一个坐标作为目标点,计算文档中字段到目标点距离大小,根据距离排序。</p>
<h2 id="分页">分页</h2>
<p>elasticsearch 默认情况下只返回top10的数据。而如果要查询更多数据就需要修改分页参数了。elasticsearch中通过修改from、size参数来控制要返回的分页结果:</p>
<ul>
<li>from:从第几个文档开始</li>
<li>size:总共查询几个文档</li>
</ul>
<h3 id="基本分页">基本分页</h3>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">GET /hotel/_search</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"query"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"match_all"</span><span class="punctuation">:</span> <span class="punctuation">{</span><span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"from"</span><span class="punctuation">:</span> <span class="number">0</span><span class="punctuation">,</span> <span class="comment">// 分页开始的位置,默认为0</span></span><br><span class="line"> <span class="attr">"size"</span><span class="punctuation">:</span> <span class="number">10</span><span class="punctuation">,</span> <span class="comment">// 期望获取的文档总数</span></span><br><span class="line"> <span class="attr">"sort"</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line"> <span class="punctuation">{</span><span class="attr">"price"</span><span class="punctuation">:</span> <span class="string">"asc"</span><span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">]</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
<h3 id="深度分页">深度分页</h3>
<p>问题说明:如果要查看第990开始的数据,Elasticsearch内部分页时,是先查询0-1000条的数据,然后截取其他的990-1000这10条数据。也就是查深度越大的数据,其实是把前面所有数据都要查出来,然后截取。传统的分页方式会导致性能问题,因为每次查询都需要重新计算和加载数据,对CPU和内存会产生非常大的压力,因此elasticsearch会禁止from+ size 超过10000的请求。</p>
<p>针对深度分页常用的一种解决办法是采用滚动查询的方式,</p>
<ul>
<li>
<p>在初始搜索请求,设置一个scroll参数指定滚动的保持时间,这个时间就是初始搜索请求和结果缓存保留时间。</p>
<p>第一次搜索:</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">POST /index/_search?scroll=<span class="number">1</span>m</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"size"</span><span class="punctuation">:</span> <span class="number">100</span><span class="punctuation">,</span> <span class="comment">// 每次返回的文档数量</span></span><br><span class="line"> <span class="attr">"query"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="comment">// 查询条件</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
</li>
<li>
<p>搜索返回的结果会返回一个<code>_scroll_id</code>值,这个值是上一次搜索返回结果的末尾位置,在下次搜索,通过传递这个<code>_scroll_id</code>值,从上次搜索结束的位置向后搜索,滚动查询。</p>
<p>后续搜索(不用再指定搜索条件了,第一次结果已经保留,只要向后继续取数据)</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">POST /_search/scroll</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"scroll"</span><span class="punctuation">:</span> <span class="string">"1m"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"scroll_id"</span><span class="punctuation">:</span> <span class="string">"_scroll_id"</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
</li>
<li>
<p>之后的搜索重复上一步,直到获取到所有需要的数据或者滚动查询的时间窗口过期。</p>
</li>
</ul>
<h2 id="高亮">高亮</h2>
<p>高亮的原理就是在搜索的关键字前后加上前端的标签,使得在网页页面上可以高亮显示。</p>
<p>通过标签在前端渲染得到的高亮效果。</p>
<p>实现:</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">GET /your_table_name/_search</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"query"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"match"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"FIELD"</span><span class="punctuation">:</span> <span class="string">"TEXT"</span> <span class="comment">// 查询条件,高亮一定要使用全文检索查询</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"highlight"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"fields"</span><span class="punctuation">:</span> <span class="punctuation">{</span> <span class="comment">// 指定要高亮的字段</span></span><br><span class="line"> <span class="attr">"FIELD"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"pre_tags"</span><span class="punctuation">:</span> <span class="string">"<em>"</span><span class="punctuation">,</span> <span class="comment">// 用来标记高亮字段的前置标签</span></span><br><span class="line"> <span class="attr">"post_tags"</span><span class="punctuation">:</span> <span class="string">"</em>"</span> <span class="comment">// 用来标记高亮字段的后置标签</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
<p><strong>注意:</strong></p>
<ul>
<li>高亮是对关键字高亮,因此<strong>搜索条件必须带有关键字</strong>,而不能是范围这样的查询。</li>
<li>默认情况下,<strong>高亮的字段,必须与搜索指定的字段一致</strong>,否则无法高亮</li>
<li>如果要对非搜索字段高亮,则需要添加一个属性:required_field_match=false</li>
</ul>
<h1>数据聚合</h1>
<p>聚合可以实现对数据的统计、分析、运算等,实现统计功能比数据库SQL方便、而且查询速度快,可以实现实时搜索效果。</p>
<h2 id="聚合种类">聚合种类</h2>
<p>聚合常见三类:</p>
<ul>
<li>桶(Bucker)聚合:对文档进行分组,类似于MySQL的<code>group by</code></li>
<li>度量(Metric)聚合:进行计算,例如求和、平均值、最小值、最大值等,类似于MySQL中聚合函数
<ul>
<li>Avg:平均值</li>
<li>Max:最大值</li>
<li>Min:最小值</li>
<li>Stats:同时求max,min,avg,sum等</li>
</ul>
</li>
<li>管道(pipeline)聚合:其他聚合的结果为基础做聚合</li>
</ul>
<blockquote>
<p>注意:参加聚合的字段必须是keyword、日期、数值、布尔类型(不可分)</p>
</blockquote>
<h2 id="Bucker聚合">Bucker聚合</h2>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">GET /indexName/_search</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"query"</span><span class="punctuation">:</span> <span class="punctuation">{</span> ... <span class="punctuation">}</span><span class="punctuation">,</span> <span class="comment">// 限定查询范围</span></span><br><span class="line"> <span class="attr">"size"</span><span class="punctuation">:</span> <span class="number">0</span><span class="punctuation">,</span> <span class="comment">// 设置size为0,结果中不包含文档,只包含聚合结果</span></span><br><span class="line"> <span class="attr">"aggs"</span><span class="punctuation">:</span> <span class="punctuation">{</span> <span class="comment">// 定义聚合</span></span><br><span class="line"> <span class="attr">"XXXAgg"</span><span class="punctuation">:</span> <span class="punctuation">{</span> <span class="comment">//给聚合起个名字</span></span><br><span class="line"> <span class="attr">"terms"</span><span class="punctuation">:</span> <span class="punctuation">{</span> <span class="comment">// 聚合的类型,按照品牌值聚合,所以选择term</span></span><br><span class="line"> <span class="attr">"field"</span><span class="punctuation">:</span> <span class="string">"text"</span><span class="punctuation">,</span> <span class="comment">// 参与聚合的字段</span></span><br><span class="line"> <span class="attr">"size"</span><span class="punctuation">:</span> <span class="number">20</span><span class="punctuation">,</span> <span class="comment">// 希望获取的聚合结果数量</span></span><br><span class="line"> <span class="attr">"order"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"_count"</span><span class="punctuation">:</span> <span class="string">"asc"</span> <span class="comment">// 按照_count升序排序</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
<ul>
<li><code>aggs</code>:代表聚合,与<code>query</code>同级,<code>query</code>的作用<strong>限定聚合的文档范围</strong></li>
<li>聚合三要素:聚合名称、聚合类型、聚合字段</li>
<li>聚合可配置属性:<code>size</code>指定聚合结果数量,<code>order</code>指定聚合结果排序,<code>field</code>指定聚合字段</li>
</ul>
<h2 id="Metric聚合">Metric聚合</h2>
<p>这个基于在桶聚合的基础上使用的聚合,是对桶内数据进行运算,相当于MySQL中<code>having</code>语句的作用。</p>
<p>这个聚合也是直接写在桶内聚合里面的。</p>
<p>基本语法如下:</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">GET /indexName/_search</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"size"</span><span class="punctuation">:</span> <span class="number">0</span><span class="punctuation">,</span> </span><br><span class="line"> <span class="attr">"aggs"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"XXXAgg"</span><span class="punctuation">:</span> <span class="punctuation">{</span> </span><br><span class="line"> <span class="attr">"terms"</span><span class="punctuation">:</span> <span class="punctuation">{</span> </span><br><span class="line"> <span class="attr">"field"</span><span class="punctuation">:</span> <span class="string">"TEXT"</span><span class="punctuation">,</span> </span><br><span class="line"> <span class="attr">"size"</span><span class="punctuation">:</span> <span class="number">20</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"order"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"XXX1Agg.avg"</span><span class="punctuation">:</span> <span class="string">"desc"</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"aggs"</span><span class="punctuation">:</span> <span class="punctuation">{</span> <span class="comment">// 对上面个指定字段的聚合的子聚合,也就是分组后对每组分别计算</span></span><br><span class="line"> <span class="attr">"XXX1Agg"</span><span class="punctuation">:</span> <span class="punctuation">{</span> <span class="comment">// 聚合名称</span></span><br><span class="line"> <span class="attr">"stats"</span><span class="punctuation">:</span> <span class="punctuation">{</span> <span class="comment">// 聚合类型,这里stats可以计算min、max、avg等</span></span><br><span class="line"> <span class="attr">"field"</span><span class="punctuation">:</span> <span class="string">"VALUE"</span> <span class="comment">// 聚合字段,指定聚合字段 对聚合字段进行计算</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
<h1>自动补全</h1>
<p>搜索时提示出与该字符有关的搜索项。</p>
<h2 id="拼音分词器">拼音分词器</h2>
<p>下载拼音分词器,可以实现中文拼音自动补全功能。</p>
<p>下载地址:<a href="https://github.com/medcl/elasticsearch-analysis-pinyin">拼音分词器|官方文档)</a></p>
<p>下载方式和之前IK分词器下载步骤一样:</p>
<ol>
<li>
<p>进入容器内部。</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">docker <span class="built_in">exec</span> -it es /bin/bash</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>在线安装拼音分词器。</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-pinyin/releases/download/v8.11.1/elasticsearch-analysis-pinyin-8.11.1.zip</span><br></pre></td></tr></table></figure>
</li>
</ol>
<p>通过指定分词器即可使用。</p>
<h2 id="自定义分词器">自定义分词器</h2>
<p>默认的拼音分词器会将每个汉语单独分为拼音,但实际使用希望是每个词条形成一条拼音,我们需要单独做个性化设置,形成自定义分词器。简单来说就是组合使用多个分词器,实现一些分词效果。</p>
<p>Elasticsearch中分词器分为三部分:</p>
<ul>
<li>character filter:tokenizer之前对文本进行处理。例如删除字符、替换字符等。</li>
<li>tokenizer:将文本按照一定的规则切割成词条。</li>
<li>tokenizer filter:将tokenizer输出的词条做进一步处理。例如大小写转换,同义词处理、拼音处理等。</li>
</ul>
<p>处理流程类似于:</p>
<p><img src="/2023/12/08/Elaticsearch/image-20231210215532715.png" alt="image-20231210215532715"></p>
<p>自定义分词器语法:(创建索引库阶段设置)</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">PUT /indexName</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"settings"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"analysis"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"analyzer"</span><span class="punctuation">:</span> <span class="punctuation">{</span> <span class="comment">// 自定义分词器</span></span><br><span class="line"> <span class="attr">"my_analyzer"</span><span class="punctuation">:</span> <span class="punctuation">{</span> <span class="comment">// 分词器名称 自定义名称</span></span><br><span class="line"> <span class="attr">"tokenizer"</span><span class="punctuation">:</span> <span class="string">"ik_max_word"</span><span class="punctuation">,</span> <span class="comment">// 指定各个阶段的分词器</span></span><br><span class="line"> <span class="attr">"filter"</span><span class="punctuation">:</span> <span class="string">"py"</span> <span class="comment">// py 这里是根据下面filter字段来写的 过滤器名称</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"filter"</span><span class="punctuation">:</span> <span class="punctuation">{</span> <span class="comment">// 自定义tokenizer filter</span></span><br><span class="line"> <span class="attr">"py"</span><span class="punctuation">:</span> <span class="punctuation">{</span> <span class="comment">// 过滤器名称</span></span><br><span class="line"> <span class="attr">"type"</span><span class="punctuation">:</span> <span class="string">"pinyin"</span><span class="punctuation">,</span> <span class="comment">// 过滤器类型,这里是pinyin 指定分词器</span></span><br><span class="line"> <span class="attr">"keep_full_pinyin"</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span> <span class="comment">// 这里参数设置可以参考官方文档</span></span><br><span class="line"> <span class="attr">"keep_joined_full_pinyin"</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"keep_original"</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"limit_first_letter_length"</span><span class="punctuation">:</span> <span class="number">16</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"remove_duplicated_term"</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"none_chinese_pinyin_tokenize"</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"mappings"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"properties"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"name"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"type"</span><span class="punctuation">:</span> <span class="string">"text"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"analyzer"</span><span class="punctuation">:</span> <span class="string">"my_analyzer"</span><span class="punctuation">,</span> <span class="comment">// 每个字段可以单独定义分词的每个阶段采用什么分词器</span></span><br><span class="line"> <span class="attr">"search_analyzer"</span><span class="punctuation">:</span> <span class="string">"ik_smart"</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
<p>使用拼音分词器需要注意的在搜索时不要使用,避免搜索到同音字,所以在设置字段的时候就要指定什么时候使用那种分词器。</p>
<h2 id="自动补全查询">自动补全查询</h2>
<p>Elasticsearch提供了[Suggesters | Elasticsearch Guide <a href="https://www.elastic.co/guide/en/elasticsearch/reference/8.11/search-suggesters.html">8.11] | Elastic| Completion Suggester</a> 查询实现自动补全功能。</p>
<p>这个查询会匹配用户输入内容开头的词条并返回。为了提高补全查询的效率,对于文档中字段的类型约束:</p>
<ul>
<li>参与补全查询的字段必须是completion类型。</li>
<li>字段的内容一般是用来补全的多个词条形成的数组。</li>
</ul>
<p>对于自动补全代码,需要在创建索引表对字段进行定义,内容是以数组形式传递。</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">PUT /indexName</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"mappings"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"properties"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"FIELD"</span><span class="punctuation">:</span><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"type"</span><span class="punctuation">:</span> <span class="string">"completion"</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
<p>搜索基础语法:</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">GET /indexName/_search</span><br><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"suggest"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"title_suggest"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"text"</span><span class="punctuation">:</span> <span class="string">"s"</span><span class="punctuation">,</span> <span class="comment">// 关键字</span></span><br><span class="line"> <span class="attr">"completion"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"field"</span><span class="punctuation">:</span> <span class="string">"title"</span><span class="punctuation">,</span> <span class="comment">// 补全查询的字段</span></span><br><span class="line"> <span class="attr">"skip_duplicates"</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span> <span class="comment">// 跳过重复的</span></span><br><span class="line"> <span class="attr">"size"</span><span class="punctuation">:</span> <span class="number">10</span> <span class="comment">// 获取前10条结果</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure>
]]></content>
<categories>
<category>技术栈</category>
</categories>
<tags>
<tag>搜索引擎</tag>
<tag>Elasticsearch</tag>
</tags>
</entry>
<entry>
<title>个人博客搭建</title>
<url>/2024/01/03/create_blog/</url>
<content><![CDATA[<p>主要介绍一个初始博客的搭建和简单next主题的配置和遇到的问题,采用git + github + hexo + hexo next主题实现的一个个人博客网站。</p>
<span id="more"></span>
<h2 id="工具准备">工具准备</h2>
<p>下载git,参考网址:<a href="https://juejin.cn/post/7086817870172782623">图文详解 Git 安装【当前最新,最详细版】 - 掘金 (juejin.cn)</a></p>
<p>下载node.js,参考网址:<a href="https://juejin.cn/post/7090056744549744676">node.js安装及环境配置 - 掘金 (juejin.cn)</a></p>
<p>然后打开git bash命令窗口输入:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">npm install -g hexo-cli</span><br></pre></td></tr></table></figure>
<h3 id="github创建仓库">github创建仓库</h3>
<ol>
<li>
<p>自己注册一个账号,开始创建仓库,可以参考<a href="https://zhuanlan.zhihu.com/p/60578464">使用 Hexo+GitHub 搭建个人免费博客教程(小白向) - 知乎 (zhihu.com)</a></p>
<p>需要注意的是仓库名称<code>xxx.github.io</code>。</p>
</li>
<li>
<p>在git上配置远程连接SSH</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">git config -global user.name "用户名"</span><br><span class="line">git config -global user.email "邮箱"</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">生成SSH密钥</span></span><br><span class="line">ssh-keygen -t rsa -C "邮箱"</span><br></pre></td></tr></table></figure>
<p>生成结果:</p>
<p>路径<code>C:\Users\电脑用户名\.ssh\id_rsa.pub</code></p>
<p><img src="/2024/01/03/create_blog/image-20231125201927788.png" alt="image-20231125201927788"></p>
<p><img src="/2024/01/03/create_blog/image-20231125202103556.png" alt="image-20231125202103556"></p>
</li>
<li>
<p>将密钥全部复制粘贴到GitHub上</p>
<p><img src="/2024/01/03/create_blog/image-20231125202323393.png" alt="image-20231125202323393"></p>
</li>
</ol>
<h2 id="初始hexo项目">初始hexo项目</h2>
<h3 id="初始创建">初始创建</h3>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">hexo init </span><br></pre></td></tr></table></figure>
<p>下载next主题</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">git clone [email protected]:theme-next/hexo-theme-next.git ./themes/next</span><br></pre></td></tr></table></figure>
<p>更改根目录下的<code>_config.yml</code>文件</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">themes:</span> <span class="string">next</span></span><br></pre></td></tr></table></figure>
<p>然后执行以下命令:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">拉取仓库内容</span></span><br><span class="line">git clone 仓库地址</span><br></pre></td></tr></table></figure>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">编译运行 本地测试</span></span><br><span class="line">hexo g</span><br><span class="line">hexo s</span><br></pre></td></tr></table></figure>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">下载hexo-devloper</span></span><br><span class="line">npm install hexo-deployer-git --save</span><br></pre></td></tr></table></figure>
<p>将根目录下<code>.config.yml</code>配置文件修改:</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">url:</span> <span class="comment"># https://xxx.github.io</span></span><br><span class="line"><span class="attr">deploy:</span></span><br><span class="line"> <span class="attr">type:</span> <span class="string">git</span></span><br><span class="line"> <span class="attr">repo:</span> <span class="comment"># https://gitee.com/<yourAccount>/<repo></span></span><br><span class="line"> <span class="attr">branch:</span> <span class="string">main</span></span><br></pre></td></tr></table></figure>
<p>配置修改后执行:(一定要先修改配置文件后在进行提交)</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">提交</span></span><br><span class="line">hexo d</span><br></pre></td></tr></table></figure>
<p>执行上述所有步骤后,就可以通过github看到一个初始状态的个人博客了。</p>
<h2 id="Next主题配置">Next主题配置</h2>
<h3 id="选择主题">选择主题</h3>
<p>主题配置文件下:</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="comment"># Schemes</span></span><br><span class="line"><span class="comment">#scheme: Muse</span></span><br><span class="line"><span class="comment">#scheme: Mist</span></span><br><span class="line"><span class="comment">#scheme: Pisces</span></span><br><span class="line"><span class="attr">scheme:</span> <span class="string">Gemini</span></span><br></pre></td></tr></table></figure>
<p>可以自行选择四种样式。</p>
<h3 id="修改博客头像">修改博客头像</h3>
<p>在<code>themes/next/source/images</code>放入设置的图片。</p>
<img src="/2024/01/03/create_blog/image-20231125150218977.png" alt="image-20231125150218977">
<p>在主题配置文件中设置路径即可:</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="comment"># Sidebar Avatar</span></span><br><span class="line"><span class="attr">avatar:</span></span><br><span class="line"> <span class="comment"># Replace the default image and set the url here.</span></span><br><span class="line"> <span class="attr">url:</span> <span class="string">/images/avatar.png</span></span><br><span class="line"> <span class="comment"># If true, the avatar will be dispalyed in circle.</span></span><br><span class="line"> <span class="attr">rounded:</span> <span class="literal">true</span></span><br><span class="line"> <span class="comment"># If true, the avatar will be rotated with the cursor.</span></span><br><span class="line"> <span class="attr">rotated:</span> <span class="literal">false</span></span><br></pre></td></tr></table></figure>
<h3 id="侧边栏社交添加">侧边栏社交添加</h3>
<p>主题配置文件夹下配置:</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">social:</span></span><br><span class="line"> <span class="comment">#GitHub: https://github.com || fab fa-github</span></span><br><span class="line"> <span class="comment">#E-Mail: mailto:[email protected] || fa fa-envelope</span></span><br><span class="line"> <span class="comment">#Weibo: https://weibo.com/yourname || fab fa-weibo</span></span><br><span class="line"> <span class="comment">#Google: https://plus.google.com/yourname || fab fa-google</span></span><br><span class="line"> <span class="comment">#Twitter: https://twitter.com/yourname || fab fa-twitter</span></span><br><span class="line"> <span class="comment">#FB Page: https://www.facebook.com/yourname || fab fa-facebook</span></span><br><span class="line"> <span class="comment">#StackOverflow: https://stackoverflow.com/yourname || fab fa-stack-overflow</span></span><br><span class="line"> <span class="comment">#YouTube: https://youtube.com/yourname || fab fa-youtube</span></span><br><span class="line"> <span class="comment">#Instagram: https://instagram.com/yourname || fab fa-instagram</span></span><br><span class="line"> <span class="comment">#Skype: skype:yourname?call|chat || fab fa-skype</span></span><br></pre></td></tr></table></figure>
<h3 id="添加菜单结构">添加菜单结构</h3>
<p>输入命令:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">hexo new page tags</span><br></pre></td></tr></table></figure>
<p>这样就可以创建一个tags目录,效果如图所示:</p>
<p><img src="/2024/01/03/create_blog/image-20231125135239747.png" alt="image-20231125135239747"></p>
<p>同理还可以创建<code>about、categories、archives</code>等菜单文件。</p>
<p>我们需要进入到每个文件目录下面去修改它<code>index.md</code>文件,修改它的类型,如图所示:</p>
<p><img src="/2024/01/03/create_blog/image-20231125135911341.png" alt="image-20231125135911341"></p>
<figure class="highlight tex"><table><tr><td class="code"><pre><span class="line">tags: tags</span><br><span class="line">categories: categories</span><br><span class="line">留言板: 将comments一栏改为true type改为guestbook</span><br></pre></td></tr></table></figure>
<p>在主题的配置文件<code>_config.yml</code>开启对应菜单:</p>
<p><img src="/2024/01/03/create_blog/image-20231125140353312.png" alt="image-20231125140353312"></p>
<p>可以设置显示数量:</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">menu_settings:</span></span><br><span class="line"> <span class="attr">icons:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">badges:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure>
<h3 id="添加搜索功能">添加搜索功能</h3>
<p>下载搜索插件:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">npm install hexo-generator-searchdb</span><br></pre></td></tr></table></figure>
<p>主题目录下配置文件<code>_config.yml</code>开启本地搜索:</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">local_search:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="comment"># If auto, trigger search by changing input.</span></span><br><span class="line"> <span class="comment"># If manual, trigger search by pressing enter key or search button.</span></span><br><span class="line"> <span class="attr">trigger:</span> <span class="string">auto</span></span><br><span class="line"> <span class="comment"># Show top n results per article, show all results by setting to -1</span></span><br><span class="line"> <span class="attr">top_n_per_article:</span> <span class="number">1</span></span><br><span class="line"> <span class="comment"># Unescape html strings to the readable one.</span></span><br><span class="line"> <span class="attr">unescape:</span> <span class="literal">false</span></span><br><span class="line"> <span class="comment"># Preload the search data when the page loads.</span></span><br><span class="line"> <span class="attr">preload:</span> <span class="literal">false</span></span><br></pre></td></tr></table></figure>
<p>根目录下<code>_config.yml</code>配置:</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="comment"># hexo-generator-searchdb</span></span><br><span class="line"><span class="attr">search:</span></span><br><span class="line"> <span class="attr">path:</span> <span class="string">search.xml</span></span><br><span class="line"> <span class="attr">field:</span> <span class="string">post</span></span><br><span class="line"> <span class="attr">format:</span> <span class="string">html</span></span><br><span class="line"> <span class="attr">limit:</span> <span class="number">10</span></span><br></pre></td></tr></table></figure>
<h3 id="添加动态背景">添加动态背景</h3>
<p>打开生成的hexo目录<code>\themes\next\layout\_layout.swig</code>文件,将代码放在<code></body></code>上面。</p>
<figure class="highlight tex"><table><tr><td class="code"><pre><span class="line">{<span class="comment">% if theme.canvas_nest %}</span></span><br><span class="line"><script type="text/javascript" src="//cdn.bootcss.com/canvas-nest.js/1.0.0/canvas-nest.min.js"></script></span><br><span class="line">{<span class="comment">% endif %}</span></span><br></pre></td></tr></table></figure>
<p>主题配置文件添加配置:</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="comment"># --------------------------------------------------------------</span></span><br><span class="line"><span class="comment"># background settings</span></span><br><span class="line"><span class="comment"># --------------------------------------------------------------</span></span><br><span class="line"><span class="comment"># add canvas-nest effect</span></span><br><span class="line"><span class="comment"># see detail from https://github.com/hustcc/canvas-nest.js</span></span><br><span class="line"><span class="attr">canvas_nest:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure>
<h3 id="增加阅读时间和文章数字统计">增加阅读时间和文章数字统计</h3>
<p>下载插件:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">npm install hexo-symbols-count-time</span><br></pre></td></tr></table></figure>
<p>根目录下配置文件添加:</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">symbols_count_time:</span></span><br><span class="line"> <span class="attr">symbols:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">time:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">total_symbols:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">total_time:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">exclude_codeblock:</span> <span class="literal">false</span></span><br><span class="line"> <span class="attr">awl:</span> <span class="number">2</span> </span><br><span class="line"> <span class="attr">wpm:</span> <span class="number">275</span></span><br><span class="line"> <span class="attr">suffix:</span> <span class="string">"mins."</span></span><br></pre></td></tr></table></figure>
<p>主题配置文件下打开开关:</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">symbols_count_time:</span></span><br><span class="line"> <span class="attr">separated_meta:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">item_text_post:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">item_text_total:</span> <span class="literal">false</span></span><br></pre></td></tr></table></figure>
<h3 id="部件配置">部件配置</h3>
<p>都在主题配置文件下</p>
<p>阅读进度条:</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">reading_progress:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="comment"># Available values: top | bottom</span></span><br><span class="line"> <span class="attr">position:</span> <span class="string">top</span></span><br><span class="line"> <span class="attr">color:</span> <span class="string">"#37c6c0"</span></span><br><span class="line"> <span class="attr">height:</span> <span class="string">3px</span></span><br></pre></td></tr></table></figure>
<p>左上角Github图标:</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">github_banner:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">permalink:</span> <span class="string">https://github.com/xxx</span></span><br><span class="line"> <span class="attr">title:</span> <span class="string">Follow</span> <span class="string">me</span> <span class="string">on</span> <span class="string">GitHub</span></span><br></pre></td></tr></table></figure>
<p>开启代码复制:</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">codeblock:</span></span><br><span class="line"> <span class="comment"># Code Highlight theme</span></span><br><span class="line"> <span class="comment"># Available values: normal | night | night eighties | night blue | night bright | solarized | solarized dark | galactic</span></span><br><span class="line"> <span class="comment"># See: https://github.com/chriskempson/tomorrow-theme</span></span><br><span class="line"> <span class="attr">highlight_theme:</span> <span class="string">normal</span></span><br><span class="line"> <span class="comment"># Add copy button on codeblock</span></span><br><span class="line"> <span class="attr">copy_button:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="comment"># Show text copy result.</span></span><br><span class="line"> <span class="attr">show_result:</span> <span class="literal">false</span></span><br><span class="line"> <span class="comment"># Available values: default | flat | mac</span></span><br><span class="line"> <span class="attr">style:</span></span><br></pre></td></tr></table></figure>
<p>文末尾版权说明</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">creative_commons:</span></span><br><span class="line"> <span class="attr">license:</span> <span class="string">by-nc-sa</span></span><br><span class="line"> <span class="attr">sidebar:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">post:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">language:</span> <span class="string">zh-CN</span></span><br></pre></td></tr></table></figure>
<p>设置回到顶部</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">back2top:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="comment"># Back to top in sidebar.</span></span><br><span class="line"> <span class="attr">sidebar:</span> <span class="literal">false</span></span><br><span class="line"> <span class="comment"># Scroll percent label in b2t button.</span></span><br><span class="line"> <span class="attr">scrollpercent:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure>
<h2 id="问题">问题</h2>
<h3 id="图片不显示">图片不显示</h3>
<p>hexo生成后图片路劲发生改变,导致了生成后文章找不到图片。</p>
<p>下载插件:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">npm install https://github.com/CodeFalling/hexo-asset-image --save</span><br></pre></td></tr></table></figure>
<p>修改根目录下配置文件:</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">post_asset_folder:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure>
<p>生成的时候可能要等一会,多刷新几次。</p>
<p>只有md文档同级下有对应文件夹来放图片就可以了。</p>
<p>如果还是不行,直接去修改<code>hexo-asset-image</code>包下的<code>index.js</code>文件:</p>
<p><img src="/2024/01/03/create_blog/image-20231125182910235.png" alt="image-20231125182910235"></p>
<p>去调整<code>index.js</code>的中路径字符串拼接的部分,视自己当前问题来合理调整。</p>
<p><strong>这里还需要注意的是根目录下的配置文件中<code>url</code>的配置:一定要是自己的仓库名,不然所有组件都会加载失败。</strong></p>
<h3 id="hexo的不支持Latex语法">hexo的不支持Latex语法</h3>
<p>我们需要进行重新选择插件进行渲染。</p>
<p>需要重新更新插件:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">npm uninstall hexo-renderer-marked --save</span><br><span class="line">npm install hexo-renderer-kramed --save</span><br></pre></td></tr></table></figure>
<p>修改主题配置文件:</p>
<img src="/2024/01/03/create_blog/image-20231127152223788.png" alt="image-20231127152223788" style="zoom:80%;">
<p>修改插件文件,路径<code>\blog\node_modules\kramed\lib\rules\inline.js</code>:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> inline = {</span><br><span class="line"> <span class="comment">// escape: /^\\([\\`*{}\[\]()#$+\-.!_>])/,</span></span><br><span class="line"> <span class="attr">escape</span>: <span class="regexp">/^\\([`*\[\]()#$+\-.!_>])/</span>,</span><br><span class="line"> <span class="attr">autolink</span>: <span class="regexp">/^<([^ >]+(@|:\/)[^ >]+)>/</span>,</span><br><span class="line"> <span class="attr">url</span>: noop,</span><br><span class="line"> <span class="attr">html</span>: <span class="regexp">/^<!--[\s\S]*?-->|^<(\w+(?!:\/|[^\w\s@]*@)\b)*?(?:"[^"]*"|'[^']*'|[^'">])*?>([\s\S]*?)?<\/\1>|^<(\w+(?!:\/|[^\w\s@]*@)\b)(?:"[^"]*"|'[^']*'|[^'">])*?>/</span>,</span><br><span class="line"> <span class="attr">link</span>: <span class="regexp">/^!?\[(inside)\]\(href\)/</span>,</span><br><span class="line"> <span class="attr">reflink</span>: <span class="regexp">/^!?\[(inside)\]\s*\[([^\]]*)\]/</span>,</span><br><span class="line"> <span class="attr">nolink</span>: <span class="regexp">/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/</span>,</span><br><span class="line"> <span class="attr">reffn</span>: <span class="regexp">/^!?\[\^(inside)\]/</span>,</span><br><span class="line"> <span class="attr">strong</span>: <span class="regexp">/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/</span>,</span><br><span class="line"> <span class="comment">// em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,</span></span><br><span class="line"> <span class="attr">em</span>: <span class="regexp">/^\*((?:\*\*|[\s\S])+?)\*(?!\*)/</span>,</span><br><span class="line"> <span class="attr">code</span>: <span class="regexp">/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/</span>,</span><br><span class="line"> <span class="attr">br</span>: <span class="regexp">/^ {2,}\n(?!\s*$)/</span>,</span><br><span class="line"> <span class="attr">del</span>: noop,</span><br><span class="line"> <span class="attr">text</span>: <span class="regexp">/^[\s\S]+?(?=[\\<!\[_*`$]| {2,}\n|$)/</span>,</span><br><span class="line"> <span class="attr">math</span>: <span class="regexp">/^\$\$\s*([\s\S]*?[^\$])\s*\$\$(?!\$)/</span>,</span><br><span class="line">};</span><br></pre></td></tr></table></figure>
<p>然后重新生成运行就可以了。</p>
<h3 id="markdown不支持上标和下标的语法">markdown不支持上标和下标的语法</h3>
<p>使用html来实现上下标,不使用<code>~~和^^</code>。</p>
]]></content>
<categories>
<category>技术栈</category>
</categories>
<tags>
<tag>BLOG</tag>
<tag>IT</tag>
</tags>
</entry>
<entry>
<title>opencv c++ 安装教程</title>
<url>/2023/12/04/opencv-c++-%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B/</url>
<content><![CDATA[<p>OpenCV安装步骤说明。</p>
<span id="more"></span>
<h1>下载安装</h1>
<p>从官方上下载对应版本的opencv<a href="https://opencv.org/releases/">Releases - OpenCV</a></p>
<img src="/2023/12/04/opencv-c++-%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B/image-20231204164457007.png" alt="image-20231204164457007" style="zoom: 50%;">
<p>解压提取到指定到文件目录下,如图:</p>
<img src="/2023/12/04/opencv-c++-%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B/image-20231204164646442.png" alt="image-20231204164646442" style="zoom:67%;">
<h1>配置环境变量</h1>
<p>找到自己的对应路径<code>D:\ProgramFiles\opencv\opencv\build\x64\vc16\bin</code>, 如图:</p>
<img src="/2023/12/04/opencv-c++-%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B/image-20231204164902549.png" alt="image-20231204164902549" style="zoom:67%;">
<p>配置到电脑的环境变量中,如图:</p>
<img src="/2023/12/04/opencv-c++-%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B/image-20231204165209790.png" alt="image-20231204165209790" style="zoom:50%;">