使用 Java-Large 文件查询 JSON 文件

2024-05-27

我正在尝试使用 java 解析下面的 JSON 文件。 我需要能够

  • 按 ID 或名称或对象中的任何字段搜索文件。
  • 也在字段中搜索空值。

搜索应返回整个对象。 该文件将会很大,并且搜索应该仍然很省时。


[
  {
    "id": 1,
    "name": "Mark Robb",
    "last_login": "2013-01-21T05:13:41 -11:30",
    "email": "[email protected] /cdn-cgi/l/email-protection",
    "phone": "12345",
    "locations": [
        "Germany",
        "Austria"
    ]
},
  {
    "id": 2,
    "name": "Matt Nish",
    "last_login": "2014-02-21T07:10:41 -11:30",
    "email": "[email protected] /cdn-cgi/l/email-protection",
    "phone": "456123",
    "locations": [
        "France",
        "Italy"
    ]
 }
]


这是我迄今为止使用杰克逊库所尝试的。

public void findById(int id) {
List<Customer> customers = objectMapper.readValue(new File("src/main/resources/customers.json"), new    TypeReference<List<Customer>>(){});

            for(Customer customer: customers) {
                if(customer.getId() == id) {
                    System.out.println(customer.getName());
                }
            }
}

我只是认为这对于一个巨大的 JSON 文件(一个文件中大约有 20000 个客户)来说不是一个有效的方法。并且可能有多个文件。搜索时间不应线性增加。 我怎样才能让这个时间变得高效呢?我应该使用其他库吗?


最有效的(CPU 和内存)解析方式是使用面向流的解析而不是对象映射。通常,需要编写更多的代码,但通常也是很划算的:) Gson 和 Jackson 都支持这种轻量级技术。另外,您应该避免在主/热路径中分配内存,以防止 GC 暂停。为了说明这个想法,我使用了一个小型的无 GC 库https://github.com/anatolygudkov/green-jelly https://github.com/anatolygudkov/green-jelly:

import org.green.jelly.*;    
import java.io.CharArrayReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;

public class SelectById {
    public static class Customer {
        private long id;
        private String name;
        private String email;

        public void clear() {
            id = 0;
            name = null;
            email = null;
        }

        public Customer makeCopy() {
            Customer result = new Customer();
            result.id = id;
            result.name = name;
            result.email = email;
            return result;
        }

        @Override
        public String toString() {
            return "Customer{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", email='" + email + '\'' +
                    '}';
        }
    }

    public static void main(String[] args) throws Exception {
        final String file = "\n" +
            "[\n" +
            "  {\n" +
            "    \"id\": 1,\n" +
            "    \"name\": \"Mark Robb\",\n" +
            "    \"last_login\": \"2013-01-21T05:13:41 -11:30\",\n" +
            "    \"email\": \"[email protected] /cdn-cgi/l/email-protection\",\n" +
            "    \"phone\": \"12345\",\n" +
            "    \"locations\": [\n" +
            "        \"Germany\",\n" +
            "        \"Austria\"\n" +
            "    ]\n" +
            "},\n" +
            "  {\n" +
            "    \"id\": 2,\n" +
            "    \"name\": \"Matt Nish\",\n" +
            "    \"last_login\": \"2014-02-21T07:10:41 -11:30\",\n" +
            "    \"email\": \"[email protected] /cdn-cgi/l/email-protection\",\n" +
            "    \"phone\": \"456123\",\n" +
            "    \"locations\": [\n" +
            "        \"France\",\n" +
            "        \"Italy\"\n" +
            "    ]\n" +
            " }\n" +
            "]\n";

        final List<Customer> selection = new ArrayList<>();

        final long selectionId = 2;

        final JsonParser parser = new JsonParser().setListener(
            new JsonParserListenerAdaptor() {
                private final Customer customer = new Customer();
                private String currentField;
                @Override
                public boolean onObjectStarted() {
                    customer.clear();
                    return true;
                }

                @Override
                public boolean onObjectMember(final CharSequence name) {
                    currentField = name.toString();
                    return true;
                }

                @Override
                public boolean onStringValue(final CharSequence data) {
                    switch (currentField) {
                        case "name":
                            customer.name = data.toString();
                            break;
                        case "email":
                            customer.email = data.toString();
                            break;
                    }
                    return true;
                }

                @Override
                public boolean onNumberValue(final JsonNumber number) {
                    if ("id".equals(currentField)) {
                        customer.id = number.mantissa();
                    }
                    return true;
                }

                @Override
                public boolean onObjectEnded() {
                    if (customer.id == selectionId) {
                        selection.add(customer.makeCopy());
                        return false; // we don't need to continue
                    }
                    return true;
                }
            }
        );

        // now let's read and parse the data with a buffer

        final CharArrayCharSequence buffer = new CharArrayCharSequence(1024);

        try (final Reader reader = new CharArrayReader(file.toCharArray())) { // replace by FileReader, for example
            int len;
            while((len = reader.read(buffer.getChars())) != -1) {
                buffer.setLength(len);
                parser.parse(buffer);
            }
        }
        parser.eoj();

        System.out.println(selection);
    }
}

它在 Java 中的运行速度应该尽可能快(以防我们无法直接使用 SIMD 指令)。要完全摆脱主路径中的内存分配(和 GC 暂停),您必须将“.toString()”(它创建 String 的新实例)替换为可重用的东西,例如 StringBuilder。

最后可能影响整体性能的是文件读取的方法。 RandomAccessFile 是 Java 中最好的选择之一。由于您的编码似乎是 ASCII,因此只需将字节转换为字符即可传递给 JsonParser。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Java-Large 文件查询 JSON 文件 的相关文章

  • 给定两个 SSH2 密钥,我如何检查它们是否属于 Java 中的同一密钥对?

    我正在尝试找到一种方法来验证两个 SSH2 密钥 一个私有密钥和一个公共密钥 是否属于同一密钥对 我用过JSch http www jcraft com jsch 用于加载和解析私钥 更新 可以显示如何从私钥 SSH2 RSA 重新生成公钥
  • 在 HTTPResponse Android 中跟踪重定向

    我需要遵循 HTTPost 给我的重定向 当我发出 HTTP post 并尝试读取响应时 我得到重定向页面 html 我怎样才能解决这个问题 代码 public void parseDoc final HttpParams params n
  • Final字段的线程安全

    假设我有一个 JavaBeanUser这是从另一个线程更新的 如下所示 public class A private final User user public A User user this user user public void
  • JAXb、Hibernate 和 beans

    目前我正在开发一个使用 Spring Web 服务 hibernate 和 JAXb 的项目 1 我已经使用IDE hibernate代码生成 生成了hibernate bean 2 另外 我已经使用maven编译器生成了jaxb bean
  • 无法展开 RemoteViews - 错误通知

    最近 我收到越来越多的用户收到 RemoteServiceException 错误的报告 我每次给出的堆栈跟踪如下 android app RemoteServiceException Bad notification posted fro
  • 使用 PHP 从 Mongo 解码 JSON

    我已经看过这个线程 PHP 解码嵌套 JSON https stackoverflow com questions 3555335 php decode nested json并没有设法用它来解决我的问题 我目前正在从 Mongo 获取 J
  • JavaMail 只获取新邮件

    我想知道是否有一种方法可以在javamail中只获取新消息 例如 在初始加载时 获取收件箱中的所有消息并存储它们 然后 每当应用程序再次加载时 仅获取新消息 而不是再次重新加载它们 javamail 可以做到这一点吗 它是如何工作的 一些背
  • 操作错误不会显示在 JSP 上

    我尝试在 Action 类中添加操作错误并将其打印在 JSP 页面上 当发生异常时 它将进入 catch 块并在控制台中打印 插入异常时出错 请联系管理员 在 catch 块中 我添加了它addActionError 我尝试在jsp页面中打
  • 路径中 File.separator 和斜杠之间的区别

    使用有什么区别File separator和一个正常的 在 Java 路径字符串中 与双反斜杠相反 平台独立性似乎不是原因 因为两个版本都可以在 Windows 和 Unix 下运行 public class SlashTest Test
  • 从 127.0.0.1 到 2130706433,然后再返回

    使用标准 Java 库 从 IPV4 地址的点分字符串表示形式获取的最快方法是什么 127 0 0 1 到等效的整数表示 2130706433 相应地 反转所述操作的最快方法是什么 从整数开始2130706433到字符串表示形式 127 0
  • Java TestNG 与跨多个测试的数据驱动测试

    我正在电子商务平台中测试一系列商店 每个商店都有一系列属性 我正在考虑对其进行自动化测试 是否有可能有一个数据提供者在整个测试套件中提供数据 而不仅仅是 TestNG 中的测试 我尝试不使用 testNG xml 文件作为机制 因为这些属性
  • 如何格式化 Json 输出

    请帮助我如何获取 JSON 输出 如下所示 costMethod Average fundingDate 2008 10 02 fundingAmount 2510959 95 代替 type sma costMethod Average
  • Java Integer CompareTo() - 为什么使用比较与减法?

    我发现java lang Integer实施compareTo方法如下 public int compareTo Integer anotherInteger int thisVal this value int anotherVal an
  • 如何在 Python 中追加到 JSON 文件?

    我有一个 JSON 文件 其中包含 67790 1 kwh 319 4 现在我创建一个字典a dict我需要将其附加到 JSON 文件中 我尝试了这段代码 with open DATA FILENAME a as f json obj js
  • Android 中麦克风的后台访问

    是否可以通过 Android 手机上的后台应用程序 服务 持续监控麦克风 我想做的一些想法 不断聆听背景中的声音信号 收到 有趣的 音频信号后 执行一些网络操作 如果前台应用程序需要的话 后台应用程序必须能够智能地放弃对麦克风的访问 除非可
  • 声明的包“”与预期的包不匹配

    我可以编译并运行我的代码 但 VSCode 中始终显示错误 早些时候有一个弹出窗口 我不记得是什么了 我点击了 全局应用 从那以后一直是这样 Output is there but so is the error The declared
  • 编译器抱怨“缺少返回语句”,即使不可能达到缺少返回语句的条件

    在下面的方法中 编译器抱怨缺少退货声明即使该方法只有一条路径 并且它包含一个return陈述 抑制错误需要另一个return陈述 public int foo if true return 5 鉴于Java编译器可以识别无限循环 https
  • JGit 检查分支是否已签出

    我正在使用 JGit 开发一个项目 我设法删除了一个分支 但我还想检查该分支是否已签出 我发现了一个变量CheckoutCommand但它是私有的 private boolean isCheckoutIndex return startCo
  • java.lang.IllegalStateException:驱动程序可执行文件的路径必须由 webdriver.chrome.driver 系统属性设置 - Similiar 不回答

    尝试学习 Selenium 我打开了类似的问题 但似乎没有任何帮助 我的代码 package seleniumPractice import org openqa selenium WebDriver import org openqa s
  • 节拍匹配算法

    我最近开始尝试创建一个移动应用程序 iOS Android 它将自动击败比赛 http en wikipedia org wiki Beatmatching http en wikipedia org wiki Beatmatching 两

随机推荐