在Java中实现内存模糊搜索的方法
最编程
2024-07-28 10:00:55
...
下面说说看到的工作项目中的代码,是这个样子的,事先查询一次数据库,将查询到的整张表的数据存到内存,以后使用时不再查询数据库,而直接操作内存中的数据,这主要用于数据库中的数据比较稳定,不会轻易改变的情况,比如法律条款,医疗术语,拿到这些数据主要是用于模糊查询,我对相关代码进行了改动,把原来固定的通过某些字段的模糊查询改为可选择通过哪些字段进行模糊查询,下面看一下代码
控制层,服务层没什么可说的,直接看代码
package study.fuzzysearch.controller;
import java.util.List;
import study.fuzzysearch.bean.User;
import study.fuzzysearch.service.UserService;
public class UserController {
public List<User> getUserByFuzzySearch(String searchStr, String[] searchFields, boolean startMatch)
{
return new UserService().getUserByFuzzySearch(searchStr, searchFields, startMatch);
}
}
package study.fuzzysearch.service;
import java.util.List;
import study.fuzzysearch.bean.User;
import study.fuzzysearch.dao.UserDao;
public class UserService {
public List<User> getUserByFuzzySearch(String searchStr, String[] searchFields, boolean startMatch)
{
return new UserDao().getUserByFuzzySearch(searchStr, searchFields, startMatch);
}
}
DAO层实现如下
package study.fuzzysearch.dao;
import java.util.List;
import study.fuzzysearch.bean.User;
import study.fuzzysearch.interf.Filter;
import study.fuzzysearch.interf.impl.FuzzyImpl;
public class UserDao {
// 模拟从数据库取数据
User[] users = new User[]{
new User("10001", "zihan", "zh"),
new User("zh002", "zuosan", "zs"),
new User("10003", "zisha", "zs"),
new User("10004", "zizhai", "zw"),
new User("10005", "zaohu", "zh"),
new User("10006", "zhanghu", "zh")
};
public List<User> getUserByFuzzySearch(String searchStr, String[] searchFields, boolean startMatch)
{
// 可以初始化一次保存起来,留以后用
FuzzyImpl<User> fuzzy = new FuzzyImpl<User>(users) {
public String getName(User t) {
return t.getUserName();
}
public String getPy(User t) {
return t.getPy();
}
public String getUserId(User t) {
return t.getUserId();
}
};
final String[] finalSearchFields = searchFields;
return fuzzy.search(searchStr, new Filter<User>() {
public String[] searchFields() {
return finalSearchFields;
}
// 这里可以定制一些情况,比如张三在黑名单里,不返回张三
public boolean match(User t) {
if(t.getUserId().equals("10006"))
return false;
return true;
}
}, startMatch);
}
}
再看下两个接口
package study.fuzzysearch.interf;
public interface Filter<T> {
public boolean match(T t);
public String[] searchFields();
}
上面的接口的match可以过滤掉无效的结果,searchFields指定通过哪些字段进行模糊查询
package study.fuzzysearch.interf;
public interface Fuzzy<T> {
String getName(T t);
String getPy(T t);
String getUserId(T t);
}
上面的接口指定可以通过名字,拼音码,id进行模糊查询,如果有更多的选择,可以增加方法
下面看一下最核心的方法FuzzyImpl类
package study.fuzzysearch.interf.impl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import study.fuzzysearch.interf.Filter;
import study.fuzzysearch.interf.Fuzzy;
public abstract class FuzzyImpl<T> implements Fuzzy<T>{
private T[] datas;
private Map<String, List<T>> nameMap = new HashMap<String, List<T>>();
private Map<String, List<T>> pyMap = new HashMap<String, List<T>>();
private Map<String, List<T>> userIdMap = new HashMap<String, List<T>>();
private Map<String, Map<String, List<T>>> allMap = new HashMap<String, Map<String, List<T>>>();
public FuzzyImpl(T[] datas)
{
this.datas = datas;
List<T> temp = null;
if(null != datas && datas.length > 0)
{
for(int i = 0; i < datas.length; i++)
{
temp = nameMap.get(getName(datas[i]));
if(temp == null)
{
temp = new ArrayList<T>();
}
temp.add(datas[i]);
nameMap.put(getName(datas[i]), temp);
temp = pyMap.get(getPy(datas[i]));
if(temp == null)
{
temp = new ArrayList<T>();
}
temp.add(datas[i]);
pyMap.put(getPy(datas[i]), temp);
temp = userIdMap.get(getUserId(datas[i]));
if(temp == null)
{
temp = new ArrayList<T>();
}
temp.add(datas[i]);
userIdMap.put(getUserId(datas[i]), temp);
}
allMap.put("py", pyMap);
allMap.put("userId", userIdMap);
allMap.put("name", nameMap);
}
}
public List<T> search(String searchStr, Filter<T> f, boolean startMatch)
{
List<T> result = new ArrayList<T>();
List<T> temp = new ArrayList<T>();
if(null != searchStr && searchStr.length() > 0)
{
String[] searchFields = f.searchFields();
if(null != searchFields && searchFields.length > 0)
{
for(int i = 0; i < searchFields.length; i++)
{
Map<String, List<T>> tempSearchMap = allMap.get(searchFields[i]);
temp.addAll(search(searchStr, tempSearchMap, startMatch));
}
Set<T> tempSet = new HashSet<T>(temp);
temp = new ArrayList<T>(tempSet);
for(int i = 0; i < temp.size(); i++)
{
if(f.match(temp.get(i)))
{
result.add(temp.get(i));
}
}
}
}
return result;
}
public List<T> search(String searchStr, Map<String, List<T>> compMap, boolean startMatch)
{
List<T> result = new ArrayList<T>();
Set<String> keys = compMap.keySet();
Iterator<String> keyIte = keys.iterator();
while(keyIte.hasNext())
{
String next = keyIte.next();
if(startMatch)
{
if(next.startsWith(searchStr))
{
result.addAll(compMap.get(next));
}
}
else
{
if(next.contains(searchStr))
{
result.addAll(compMap.get(next));
}
}
}
return result;
}
public T[] getAllDatas()
{
return datas;
}
}
构造器中将名字,拼音码,ID分别存在了Map中,而且相同的名字,拼音码,ID存在了一起,这样减小了查询时的次数,search方法根据searchFields从名字,拼音码或者ID的Map中查询结果,并将结果合并去重得到最终结果
再看一下测试代码
package study.fuzzysearch.test;
import study.fuzzysearch.controller.UserController;
public class Test {
public static void main(String[] args)
{
// getUserByFuzzySearch
UserController controller = new UserController();
System.out.println(controller.getUserByFuzzySearch("zh", new String[]{"name", "userId", "py"}, true));
System.out.println(controller.getUserByFuzzySearch("zh", new String[]{"name", "py"}, false));
}
}
结果如下
可以对照着users的内容分析结果
代码是jdk5.0下的,所以没有用到什么高级特性,其中值得说的地方就是Fuzzy接口中的方法,里面的方法实现是在新建FuzzyImpl对象的时候,因为这时会确定要进行模糊查询的对象是什么,从而得到对象的名字,拼音码,ID,这里算是个技巧了,在对象不同的情况下通过统一的方法获取想要的数据,至于Filter接口,是用来确定查询范围与结果范围的。
好了,就说到这里吧,有喜欢的评论一下吧。
推荐阅读
-
在 ts 中实现类 java hashmap 的简单方法
-
Java 8新特性探究(十三)JavaFX 8新特性以及开发2048游戏-JavaFX历史## 跟java在服务器端和web端成绩相比,桌面一直是java的软肋,于是Sun公司在2008年推出JavaFX,弥补桌面软件的缺陷,请看下图JavaFX一路走过来的改进 从上图看出,一开始推出时候,开发者需使用一种名为JavaFX Script的静态的、声明式的编程语言来开发JavaFX应用程序。因为JavaFX Script将会被编译为Java bytecode,程序员可以使用Java代码代替。 JavaFX 2.0之后的版本摒弃了JavaFX Script语言,而作为一个Java API来使用。因此使用JavaFX平台实现的应用程序将直接通过标准Java代码来实现。 JavaFX 2.0 包含非常丰富的 UI 控件、图形和多媒体特性用于简化可视化应用的开发,WebView可直接在应用中嵌入网页;另外 2.0 版本允许使用 FXML 进行 UI 定义,这是一个脚本化基于 XML 的标识语言。 从JDK 7u6开始,JavaFx就与JDK捆绑在一起了,JavaFX团队称,下一个版本将是8.0,目前所有的工作都已经围绕8.0库进行。这是因为JavaFX将捆绑在Java 8中,因此该团队决定跳过几个版本号,迎头赶上Java 8。 ##JavaFx8的新特性 ## ###全新现代主题:Modena 新的Modena主题来替换原来的Caspian主题。不过在Application的start方法中,可以通过setUserAgentStylesheet(STYLESHEET_CASPIAN)来继续使用Caspian主题。 参考http://fxexperience.com/2013/03/modena-theme-update/ ###JavaFX 3D 在JavaFX8中提供了3D图像处理API,包括Shape3D (Box, Cylinder, MeshView, Sphere子类),SubScene, Material, PickResult, LightBase (AmbientLight 和PointLight子类),SceneAntialiasing等。Camera类也得到了更新。从JavaDoc中可以找到更多信息。 ###富文本 强化了富文本的支持 ###TreeTableView ###日期控件DatePicker 增加日期控件 ###用于 CSS 结构的公共 API
-
挂载在Linux中的作用及实现方法独到详解
-
Java实现大顶堆:理解大顶堆在Java中的含义
-
配置HP FC存储设备多路径驱动的方法在linux和Windows操作系统中即可实现
-
14-傅里叶变换的代码实现-一、numpy实现傅里叶变换和逆傅里叶变换 1.numpy实现傅里叶变换numpy.fft.fft2实现傅里叶变换,返回一个复数数组(complex ndarray),也就是频谱图像numpy.fft.fftshift将零频率分量移到频谱中心(将左上角的低频区域,移到中心位置) 20*np.log(np.abs(fshift))设置频谱的范围。可以理解为,之前通过傅里叶变换得到复数的数组,是不能通过图像的方法展示出来的,需要转换为灰度图像(映射到[0,255]区间)需要注意的是1> 傅里叶得到低频、高频信息,针对低频、高频处理能够实现不同的目的2> 傅里叶过程是可逆的,图像经过傅里叶变换、逆傅里叶变换后,能够恢复到原始图像3> 在频域对图像进行处理,在频域的处理会反映在逆变换图像上 # 将绘制的图显示在窗口 %matplotlib qt5 import cv2 import numpy as np import matplotlib.pyplot as plt img = cv2.imread(r"image\lena.bmp",cv2.IMREAD_GRAYSCALE) # 傅里叶变换 f = np.fft.fft2(img) # 移动中心位置 fshift = np.fft.fftshift(f) # 调整值范围 result = 20*np.log(np.abs(fshift)) plt.subplot(1,2,1) plt.imshow(img,cmap=plt.cm.gray) plt.title("original") plt.axis("off") plt.subplot(1,2,2) plt.imshow(result,cmap=plt.cm.gray) plt.title("result") plt.axis("off") plt.show 傅里叶变换的频谱图像: 2.numpy实现逆傅里叶变换numpy.fft.ifft2实现逆傅里叶变换,返回一个复数数组(complex ndarray)numpy.fft.ifftshiftfftshift函数的逆函数,将中心位置的低频,重新移到左上角iimg = np.abs(逆傅里叶变化结果)设置值的范围,映射到[0,255]区间 # 将绘制的图显示在窗口 %matplotlib qt5 import cv2 import numpy as np import matplotlib.pyplot as plt img = cv2.imread(r"image\boat.bmp",cv2.IMREAD_GRAYSCALE) # 傅里叶变换 f = np.fft.fft2(img) fshift = np.fft.fftshift(f) # 逆傅里叶变换 ishift = np.fft.ifftshift(fshift) iimg = np.fft.ifft2(ishift) iimg = np.abs(iimg) plt.subplot(1,2,1) plt.imshow(img,cmap=plt.cm.gray) plt.title("original") plt.axis("off") plt.subplot(1,2,2) plt.imshow(iimg,cmap=plt.cm.gray) plt.title("iimg") plt.axis("off") plt.show 将一副图像,进行傅里叶变换和逆傅里叶变换后,进行对比(一样的) 实例:通过numpy实现高通滤波,保留图像的边缘信息 获取图像的形状rows,cols = img.shape获取图像的中心点crow,ccol = int(rows/2),int(cols/2)将频谱图像的中心区域(低频区域)设置为0(黑色)fshift[crow-30:crow+30,ccol-30:ccol+30] = 0 # 将绘制的图显示在窗口 %matplotlib qt5 import cv2 import numpy as np import matplotlib.pyplot as plt img = cv2.imread(r"image\boat.bmp",cv2.IMREAD_GRAYSCALE) # 傅里叶变换 f = np.fft.fft2(img) fshift = np.fft.fftshift(f) # 高通滤波 rows,cols = img.shape crow,ccol = int(rows/2),int(cols/2) fshift[crow-30:crow+30,ccol-30:ccol+30] = 0 # 逆傅里叶变换 ishift = np.fft.ifftshift(fshift) iimg = np.fft.ifft2(ishift) iimg = np.abs(iimg) plt.subplot(1,2,1) plt.imshow(img,cmap=plt.cm.gray) plt.title("original") plt.axis("off") plt.subplot(1,2,2) plt.imshow(iimg,cmap=plt.cm.gray) plt.title("iimg") plt.axis("off") plt.show 使用numpy实现高通滤波的实验结果: 二、opencv实现傅里叶变换和逆傅里叶变换 1.opencv实现傅里叶变换 返回结果 = cv2.dft(原始图像,转换标识)1> 返回结果:是双通道的,第一个通道是结果的实数部分,第二个通道是结果的虚数部分2> 原始图像:输入图像要首先转换成np.float32(img)格式3> 转换标识:flags = cv2.DFT_COMPLEX_OUTPUT,输出一个复数阵列numpy.fft.fftshift将零频率分量移到频谱中心(将左上角的低频区域,移到中心位置)调整频谱的范围,将上面频谱图像的复数数组,转换为可以显示的灰度图像(映射到[0,255]区间)返回值 = 20*np.log(cv2.magnitude(参数1,参数2))1> 参数1:浮点型X坐标值,也就是实部2> 参数2:浮点型Y坐标值,也就是虚部 # 将绘制的图显示在窗口 %matplotlib qt5 import cv2 import numpy as np import matplotlib.pyplot as plt img = cv2.imread(r"image\lena.bmp",cv2.IMREAD_GRAYSCALE) # 傅里叶变换 dft = cv2.dft(np.float32(img),flags = cv2.DFT_COMPLEX_OUTPUT) # 移动中心位置 dftShift = np.fft.fftshift(dft) # 调整频谱的范围 result = 20*np.log(cv2.magnitude(dftShift[:,:,0],dftShift[:,:,1])) plt.subplot(1,2,1) plt.imshow(img,cmap=plt.cm.gray) plt.title("original") plt.axis("off") plt.subplot(1,2,2) plt.imshow(result,cmap=plt.cm.gray) plt.title("result") plt.axis("off") plt.show 傅里叶变换的频谱图像: 2.opencv实现逆傅里叶变换返回结果 = cv2.idft(原始数据)1> 返回结果:取决于原始数据的类型和大小2> 原始数据:实数或者复数均可numpy.fft.ifftshiftfftshift函数的逆函数,将中心位置的低频,重新移到左上角调整频谱的范围,映射到[0,255]区间返回值 = cv2.magnitude(参数1,参数2)1> 参数1:浮点型X坐标值,也就是实部2> 参数2:浮点型Y坐标值,也就是虚部 # 将绘制的图显示在窗口 %matplotlib qt5 import cv2 import numpy as np import matplotlib.pyplot as plt img = cv2.imread(r"image\lena.bmp",cv2.IMREAD_GRAYSCALE) # 傅里叶变换 dft = cv2.dft(np.float32(img),flags = cv2.DFT_COMPLEX_OUTPUT) dftShift = np.fft.fftshift(dft) # 逆傅里叶变换 ishift = np.fft.ifftshift(dftShift) iimg = cv2.idft(ishift) iimg = cv2.magnitude(iimg[:,:,0],iimg[:,:,1]) plt.subplot(1,2,1) plt.imshow(img,cmap=plt.cm.gray) plt.title("original") plt.axis("off") plt.subplot(1,2,2) plt.imshow(iimg,cmap=plt.cm.gray) plt.title("inverse") plt.axis("off") plt.show 将一副图像,进行傅里叶变换和逆傅里叶变换后,进行对比(一样的) 实例:通过opencv实现低通滤波,模糊一副图像
-
在Java中,部分文字在转码过程中出现乱码的情况修复方法
-
在Java JSP中实现打印功能的技巧与代码示例
-
在JSP中引入Java文件的方法
-
在JSP中引入Java和Vue的实现方法