简体   繁体   English

为什么从Web模块调用Lucene IndexWriter时没有更新索引?

[英]Why did Lucene IndexWriter did not update the index when called from a Web Module?

I have a strange problem with a Web Project using Lucene. 我对使用Lucene的Web项目有一个奇怪的问题。 I have written a bean which writes the data of a business object into Lucene. 我编写了一个将业务对象数据写入Lucene的bean。 The business data is provided by the web front end. 业务数据由Web前端提供。 This all works very fine. 这一切都很好。 But in some rarely cases the business object is not added into the index. 但是在极少数情况下,业务对象不会添加到索引中。 It seems that this happens in cases when multiple users are accessing the bean. 似乎在多个用户访问Bean的情况下会发生这种情况。

My bean uses static methods creating the Lucene IndexWriter and creating a Lucene Document on base of my business object. 我的bean使用静态方法创建Lucene IndexWriter并在我的业务对象的基础上创建Lucene Document。 I thought making all methods static is enough to become thread save. 我认为使所有方法静态化就足以节省线程。 But now I wonder if it is necessary to make my update method also 'synchronized' to avoid conflicts with other threads? 但是现在我想知道是否有必要使我的更新方法也“同步”以避免与其他线程发生冲突? In the cases when the object is not written into the index there are no exceptions thrown from lucene. 在没有将对象写入索引的情况下,lucene不会引发任何异常。 So I can not say what happens behind my layer. 所以我不能说在我的图层后面发生了什么。

My update method looks like this: 我的更新方法如下所示:

public static boolean updateWorklist(ItemCollection workitem) throws PluginException {

        IndexWriter awriter = null;
        // try loading imixs-search properties
        Properties prop = loadProperties();
        if (prop.isEmpty())
            return false;

        try {
            awriter = createIndexWriter(prop);

            // create term
            Term term = new Term("$uniqueid", workitem.getItemValueString("$uniqueid"));
            // test if document should be indexed or not
            if (matchConditions(prop, workitem)) {
                logger.fine("add workitem '" + workitem.getItemValueString(EntityService.UNIQUEID) + "' into index");
                awriter.updateDocument(term, createDocument(workitem));
            } else {
                logger.fine("remove workitem '" + workitem.getItemValueString(EntityService.UNIQUEID) + "' into index");
                awriter.deleteDocuments(term);
            }
        } catch (IOException luceneEx) {
            // close writer!
            logger.warning(" Lucene Exception : " + luceneEx.getMessage());

            throw new PluginException(LucenePlugin.class.getSimpleName(), INVALID_INDEX,
                    "Unable to update search index", luceneEx);

        } finally {

            if (awriter != null) {
                logger.fine(" close writer");
                try {
                    awriter.close();
                } catch (CorruptIndexException e) {
                    throw new PluginException(LucenePlugin.class.getSimpleName(), INVALID_INDEX,
                            "Unable to update search index", e);
                } catch (IOException e) {
                    throw new PluginException(LucenePlugin.class.getSimpleName(), INVALID_INDEX,
                            "Unable to update search index", e);
                }

            }
        }

        logger.fine(" update worklist successfull");
        return true;
    }

.....

    public static IndexWriter createIndexWriter(Properties prop)
            throws IOException {

        /**
         * Read configuration
         */
        // String sLuceneVersion = prop.getProperty("Version", "LUCENE_45");

        String sIndexDir = prop.getProperty("lucence.indexDir");
        String sFulltextFieldList = prop
                .getProperty("lucence.fulltextFieldList");
        String sIndexFieldListAnalyse = prop
                .getProperty("lucence.indexFieldListAnalyze");
        String sIndexFieldListNoAnalyse = prop
                .getProperty("lucence.indexFieldListNoAnalyze");

        logger.fine("IndexDir:" + sIndexDir);
        logger.fine("FulltextFieldList:" + sFulltextFieldList);
        logger.fine("IndexFieldListAnalyse:" + sIndexFieldListAnalyse);
        logger.fine("IndexFieldListNoAnalyse:" + sIndexFieldListNoAnalyse);
        // compute search field list
        StringTokenizer st = new StringTokenizer(sFulltextFieldList, ",");
        searchFieldList = new ArrayList<String>();
        while (st.hasMoreElements()) {
            String sName = st.nextToken().toLowerCase();
            // do not add internal fields
            if (!"$uniqueid".equals(sName) && !"$readaccess".equals(sName))
                searchFieldList.add(sName);
        }

        // compute Index field list (Analyze)
        st = new StringTokenizer(sIndexFieldListAnalyse, ",");
        indexFieldListAnalyse = new ArrayList<String>();
        while (st.hasMoreElements()) {
            String sName = st.nextToken().toLowerCase();
            // do not add internal fields
            if (!"$uniqueid".equals(sName) && !"$readaccess".equals(sName))
                indexFieldListAnalyse.add(sName);
        }

        // compute Index field list (Analyze)
        st = new StringTokenizer(sIndexFieldListNoAnalyse, ",");
        indexFieldListNoAnalyse = new ArrayList<String>();
        while (st.hasMoreElements()) {
            String sName = st.nextToken().toLowerCase();
            // do not add internal fields
            if (!"$uniqueid".equals(sName) && !"$readaccess".equals(sName))
                indexFieldListNoAnalyse.add(sName);
        }

        /**
         * Now create a IndexWriter Instance
         */
        Directory indexDir = createIndexDirectory(prop);

        Analyzer analyzer = new StandardAnalyzer();
        IndexWriterConfig indexWriterConfig = new IndexWriterConfig(
                Version.LATEST, analyzer);

        // set the WriteLockTimeout to wait for a write lock (in milliseconds)
        // for this instance. 10 seconds!
        indexWriterConfig.setWriteLockTimeout(10000);

        return new IndexWriter(indexDir, indexWriterConfig);
    }

....

public static boolean matchConditions(Properties prop, ItemCollection aworktiem) {

    String typePattern = prop.getProperty("lucence.matchingType");
    String processIDPattern = prop.getProperty("lucence.matchingProcessID");

    String type = aworktiem.getItemValueString("Type");
    String sPid = aworktiem.getItemValueInteger("$Processid") + "";

    // test type pattern
    if (typePattern != null && !"".equals(typePattern) && !type.matches(typePattern)) {
        logger.fine("Lucene type '" + type + "' did not match pattern '" + typePattern + "'");
        return false;
    }

    // test $processid pattern
    if (processIDPattern != null && !"".equals(processIDPattern) && !sPid.matches(processIDPattern)) {
        logger.fine("Lucene $processid '" + sPid + "' did not match pattern '" + processIDPattern + "'");

        return false;
    }
    return true;
}

.... Edit 20.Jan: I added the IndexWriter method into the code example. .... 编辑20.Jan:我在代码示例中添加了IndexWriter方法。 My property file is empty and did not provide any lucene settings to the IndexWriter 我的属性文件为空,没有为IndexWriter提供任何Lucene设置

Edit 21.Jan: I added the matchConditions method 编辑21.Jan:我添加了matchConditions方法

As explained by @maksim07, the problem in my implementation was the use of static variables and methods. 正如@ maksim07所解释的,我实现中的问题是使用静态变量和方法。 So the createDocument method could observe empty searchFieldList, indexFieldListAnalyse, indexFieldListNoAnalyse collections since there was a race condition. 因此,由于存在竞争条件,因此createDocument方法可以观察到空的searchFieldList,indexFieldListAnalyse和indexFieldListNoAnalyse集合。

Finally I re-implemented the code by using the singleton pattern with a separate init() method where I initialized all the values of my member variables. 最后,我通过使用单独的init()方法使用单例模式来重新实现代码,在该方法中,我初始化了成员变量的所有值。 Using a Singleton EJB makes the usage of a singleton pattern very easy and guaranties that all method calls are synchronized by the default behavior of the EJB container. 使用Singleton EJB使得使用Singleton模式非常容易,并且可以确保所有方法调用都通过EJB容器的默认行为进行同步。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM