ElasticSearch中文搜索时只支持单个字符如何解决?(已解决)

本文介绍了如何为Elasticsearch安装IK分词器以支持中文搜索。首先从GitHub下载对应版本的IK插件并解压到plugins目录,然后重启Elasticsearch。接着,在新建index时配置mapping,特别是对需要中文搜索的字段如'content',设置ik_max_word和ik_smart两种分词器。注意,已导入数据的index无法直接修改mapping。在Java中,搜索时应避免使用TermQueryBuilder,而改用MatchPhraseQueryBuilder进行完全匹配。最后,通过示例展示了查询语句的正确写法,成功解决了中文搜索问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.问题原因:ES默认分词规则不能支持中文,通过安装IK Analysis for Elasticsearch支持中文分词。

2.下载地址https://github.com/medcl/elasticsearch-analysis-ik/releases  对应elasticsearch版本下载相应的IK版本

 3.下载后解压到elasticsearch的plugins文件下(这里我建立一个ik文件)

4. 重启elasticsearch

出现图中这个说明插件ik安装成功 

5.elasticsearch不能再已经导入数据的index中去修改mapping,所以建立index之后立即配置分词器字段,然后再导入数据。

6.映射字段

PUT /chatting/_mapping
{
 "properties": {
  "create_time":{
 "type": "date",
 "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
 },
 "update_time":{
 "type": "date",
 "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
 },
        "content": {
          "type": "text",
          "fields": {
            "ik_max_analyzer": { 
              "type": "text",
              "analyzer": "ik_max_word",
              "search_analyzer": "ik_max_word"
            },
            "ik_smart_analyzer": {  
              "type": "text",
              "analyzer": "ik_smart" 
            }
          }
        }
 } }

其中的content字段就是需要中文搜索的字段 

7.term不会分词,keyword字段也不分词,安装了ik分词器,ik分词器是会默认分词的,所以java中就不能再使用TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery(“title”,keyword);这种方法了,应该换成 MatchPhraseQueryBuilder matchPhraseQueryBuilder = QueryBuilders.matchPhraseQuery(“title”, keyword);完全匹配的模式!!!

 若是通过工具命令就换成这种查询

GET /chatting/_search
{
   "query": {
        "match_phrase": {
            "content": {
            	"query": "不是不是吧"
            }
        }
    },
    "from": 0, 
    "size": 20
}

最后就解决了。。。

<think>我们之前修改了代码,使其能够处理单个字符。现在用户需要发送字符串(例如"LED1")来控制LED。因此,我们需要修改中断服务程序,使其能够接收并解析字符串命令。 主要思路: 1. 在中断服务程序中,我们仍然需要接收每一个字符,并将它们存储在一个缓冲区中。 2. 当接收到一个特定的结束符(例如换行符'\n'或回车符'\r'),表示一个完整的命令字符串已经接收完毕。 3. 然后,我们可以解析整个字符串,并根据命令内容设置相应的标志(如signNum)。 注意:由于8051资源有限,我们需要考虑缓冲区的大小以及防止溢出。 修改步骤: - 定义缓冲区大小,并添加一个缓冲区索引。 - 在中断服务程序中,每接收一个字符,将其存入缓冲区,并检查是否达到结束符。 - 当接收到结束符,设置一个标志,表示可以处理命令了。注意,在中断服务程序中应尽量少做耗操作,所以通常设置标志,在主循环中处理命令。 - 主循环中检查命令处理标志,然后解析缓冲区中的字符串,并执行相应操作。 以下为修改后的代码示例: ```c #include<reg52.h> sfr IPH=0xB7; #define BEEP_ON BEEP=0; #define BEEP_OFF BEEP=1; sbit LED1=P2^4; sbit LED2=P2^5; sbit LED3=P2^6; sbit LED4=P2^7; sbit SegmentG1=P2^3; sbit SegmentG2=P2^2; sbit SegmentG3=P2^1; sbit SegmentG4=P2^0; sbit KEY1=P3^2; sbit BEEP=P1^0; static char arrLetter[]="Hello World "; static unsigned int signNum=0; // 定义串口接收缓冲区 #define BUFFER_SIZE 20 static unsigned char s_uartBuffer[BUFFER_SIZE]; static unsigned char s_bufferIndex = 0; static bit s_commandReceived = 0; // 命令接收完成标志 static void InitInterrupt() { ES=1; EA=1; } static void InitUART() { SCON=0x50; TMOD=0x20; PCON=0x80;//设置波特率加倍 TL1=0xF3;//波特率为4800 TH1=TL1; TR1=1; } void main() { InitInterrupt(); InitUART(); while(1) { // 如果接收到完整命令 if (s_commandReceived) { // 解析命令 if (strncmp(s_uartBuffer, "LED1", 4) == 0) { signNum = 1; } else if (strncmp(s_uartBuffer, "LED2", 4) == 0) { signNum = 2; } else if (strncmp(s_uartBuffer, "LED3", 4) == 0) { signNum = 3; } else if (strncmp(s_uartBuffer, "LED4", 4) == 0) { signNum = 4; } // 处理完命令后重置标志和缓冲区 s_commandReceived = 0; s_bufferIndex = 0; } // 根据signNum翻转LED if(signNum != 0){ if(1 == signNum) { LED1 = ~LED1; } else if(2 == signNum) { LED2 = ~LED2; } else if(3 == signNum) { LED3 = ~LED3; } else if(4 == signNum) { LED4 = ~LED4; } signNum = 0; } } } void UART_Handler() interrupt 4 { if (RI) { RI = 0; unsigned char received = SBUF; // 如果收到回车符('\r')或换行符('\n'),则认为命令结束 if (received == '\r' || received == '\n') { // 在字符串末尾添加结束符 if (s_bufferIndex < BUFFER_SIZE-1) { s_uartBuffer[s_bufferIndex] = '\0'; } else { s_uartBuffer[BUFFER_SIZE-1] = '\0'; } s_commandReceived = 1; // 设置命令接收完成标志 s_bufferIndex = 0; // 重置索引,为下一次接收做准备 } else { // 将字符存入缓冲区 if (s_bufferIndex < BUFFER_SIZE-1) { s_uartBuffer[s_bufferIndex] = received; s_bufferIndex++; } else { // 缓冲区已满,可以选择丢弃或者处理(这里我们选择丢弃并重置) s_bufferIndex = 0; } } // 回显接收到的字符(可选) TI = 0; SBUF = received; while (!TI); TI = 0; } else if (TI) { TI = 0; // 发送中断标志清除 } } ``` ### 注意事项: 1. 上述代码使用了`strncmp`函数,需要包含`string.h`头文件(在51中可能是`<string.h>`或者编译器特定的头文件)。 2. 如果编译器不支持标准库函数,可以自行实现简单的字符串比较。 3. 回显功能可以根据需要关闭,以减少中断服务程序的间。 4. 注意缓冲区大小,防止溢出。 ### 自行实现字符串比较函数(如果编译器不支持): ```c // 简单的字符串比较函数,比较前n个字符 bit strncmp(const unsigned char *s1, const unsigned char *s2, unsigned char n) { unsigned char i; for (i=0; i<n; i++) { if (s1[i] != s2[i]) return 1; // 不相等 if (s1[i] == '\0') // 如果提前结束 return 1; } return 0; // 相等 } ``` ### 问题: 1. 在中断服务程序中,我们进行了回显操作(发送数据),这可能会增加中断处理间。如果数据量较大,可能会丢失数据。如何优化? 2. 如果同有多个LED命令快速发送,缓冲区可能会被覆盖。如何设计一个环形缓冲区来处理连续的数据流? 3. 在8051单片机中,使用字符串比较函数可能会消耗较多资源(尤其是大字符串)。有没有更高效的命令解析方法? 4. 如果用户发送的命令超过缓冲区大小,我们如何处理这种情况? §§相关问题§§ 1. 如何修改代码以实现多个LED同控制(例如发送命令"LED1_ON"和"LED1_OFF")? 2. 在串口通信中,如何处理连续发送的多条命令(例如"LED1 LED2 LED3")? 3. 如果希望命令不区分大小写(如"led1"和"LED1"效果相同),应如何修改代码? 4. 在资源有限的51单片机上,如何设计命令解析器以支持更多指令?</think>### 解决字符串命令接收问题 针对您需要发送字符串(如"LED1")而非单个字符的需求,以下是完整的解决方案: ```c #include<reg52.h> #include<string.h> // 添加字符串处理库 sfr IPH=0xB7; #define BUFFER_SIZE 20 // 定义命令缓冲区大小 sbit LED1=P2^4; sbit LED2=P2^5; sbit LED3=P2^6; sbit LED4=P2^7; // 全局变量 static unsigned char s_iBuffer[BUFFER_SIZE]; // 命令缓冲区 static unsigned char s_iCount = 0; // 缓冲区索引 static bit s_commandReady = 0; // 命令就绪标志 void UART_Handler() interrupt 4 { if(RI) { RI = 0; unsigned char received = SBUF; // 存储接收到的字符(非换行回车符) if(received != '\r' && received != '\n') { if(s_iCount < BUFFER_SIZE - 1) { s_iBuffer[s_iCount] = received; s_iCount++; } } // 回显接收到的字符 TI = 0; SBUF = received; while(!TI); TI = 0; // 检测命令结束符(回车或换行) if(received == '\r' || received == '\n') { s_iBuffer[s_iCount] = '\0'; // 添加字符串结束符 s_commandReady = 1; // 设置命令就绪标志 s_iCount = 0; // 重置缓冲区索引 } } } void ProcessCommand() { // 比较接收到的命令 if(strcmp(s_iBuffer, "LED1") == 0) { LED1 = ~LED1; } else if(strcmp(s_iBuffer, "LED2") == 0) { LED2 = ~LED2; } else if(strcmp(s_iBuffer, "LED3") == 0) { LED3 = ~LED3; } else if(strcmp(s_iBuffer, "LED4") == 0) { LED4 = ~LED4; } // 添加更多命令处理... s_commandReady = 0; // 清除命令标志 } void main() { // 初始化代码保持不变... while(1) { if(s_commandReady) { ProcessCommand(); // 处理接收到的命令 } } } ``` ### 关键改进说明: 1. **命令缓冲区机制**: - 创建静态缓冲区 `s_iBuffer` 存储接收的字符串 - 使用 `s_iCount` 跟踪缓冲区位置 - 添加字符串结束符 `\0` 形成标准C字符串 2. **命令结束检测**: - 检测回车符 `\r` 或换行符 `\n` 作为命令结束标志 - 设置 `s_commandReady` 标志通知主程序 3. **命令处理函数**: - 在主循环中调用 `ProcessCommand()` - 使用 `strcmp()` 进行字符串比较 - 支持完整命令如 "LED1"、"LED2" 等 4. **回显机制**: - 实回显接收的字符(可选功能) - 帮助调试和确认数据传输 ### 使用方式: 1. 发送 "LED1" + 回车 → LED1 状态翻转 2. 发送 "LED2" + 回车 → LED2 状态翻转 3. 以此类推... > 注意:实际使用,请根据您的串口终端设置选择正确的换行符(通常为 `\r\n` 或 `\n`)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值